Goal

02A pairs experiments

Read the pairwise competitive outcomes determined by colony counting on TSA

Generate table for manual key-in

Then I manually checked the scanned plate images of competitive pairs. The plate images are saved in folder plate_scan/high_order_plate_scan/ and divided according the experimental batches.

Batch Community
B2 2.6, 2.8, 7.1, 8.4, 10.2, 11.1
C 11.1 isolate 1
C2 11.2
D 1.2, 1.4, 1.6, 1.7, 4.1, 11.5

There are 186x3=558 outcomes of pairwise competitions.

Rows: 558 Columns: 11
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Experiment, Community
dbl (8): Isolate1, Isolate2, Isolate1Freq, Isolate2Freq, ColonyCount, ColonyCount1, ColonyCount2, D...
lgl (1): Contamination

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

67 pairs without determined outcomes of pairwise competitions will be determined by using CASEU method

186 pair IDs saved in pairs_ID

Rows: 186 Columns: 3
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (2): Isolate1, Isolate2

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Ambiguous pairs and isolates on TSA agar plates

There are 67 pair-freqs that I don’t know the competitive outcomes by TSA plate counting. The ambiguous pairs will be later examined by using selective media or Sanger sequencing.

Rows: 67 Columns: 7
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Experiment, Community
dbl (4): Isolate1, Isolate2, Isolate1Freq, Isolate2Freq
lgl (1): Contamination

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

28 pairs

`summarise()` has grouped output by 'Community', 'Isolate1'. You can override using the `.groups` argument.

36 isolates involved in the ambiguous pairs.

Rows: 36 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Community, ExpID
dbl (2): Isolate, ID

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Map pairs and isolates to the DW96 plate layout

Rows: 13 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (3): CommunitySize, CommunityPairSize, CommunitiyMotifSize

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Each plate has 96 rows and has the following variables

Rows: 1248 Columns: 10
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (7): Experiment, PlateLayout, Well, Community, Isolate1, Isolate2, Plate
dbl (2): Isolate1Freq, Isolate2Freq
lgl (1): MixIsolate

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
spec_tbl_df [1,248 × 10] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ Experiment  : chr [1:1248] "Transitivity_B2" "Transitivity_B2" "Transitivity_B2" "Transitivity_B2" ...
 $ PlateLayout : chr [1:1248] "933" "933" "933" "933" ...
 $ Well        : chr [1:1248] "A01" "A02" "A03" "A04" ...
 $ MixIsolate  : logi [1:1248] TRUE TRUE TRUE TRUE TRUE TRUE ...
 $ Community   : chr [1:1248] "C11R1" "C11R1" "C11R1" "C11R1" ...
 $ Isolate1    : chr [1:1248] "1" "1" "1" "1" ...
 $ Isolate2    : chr [1:1248] "1" "2" "3" "4" ...
 $ Plate       : chr [1:1248] "P1" "P1" "P1" "P1" ...
 $ Isolate1Freq: num [1:1248] 50 50 50 50 50 50 50 50 50 50 ...
 $ Isolate2Freq: num [1:1248] 50 50 50 50 50 50 50 50 50 50 ...
 - attr(*, "spec")=
  .. cols(
  ..   Experiment = col_character(),
  ..   PlateLayout = col_character(),
  ..   Well = col_character(),
  ..   MixIsolate = col_logical(),
  ..   Community = col_character(),
  ..   Isolate1 = col_character(),
  ..   Isolate2 = col_character(),
  ..   Plate = col_character(),
  ..   Isolate1Freq = col_double(),
  ..   Isolate2Freq = col_double()
  .. )
 - attr(*, "problems")=<externalptr> 

Read plate layout by batch

Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.

Plate layout that takes different initial frequencies:

  • P1 is 50%:50%.

  • P2 and P3 are identical and whose rows are 95% and columns are 5%.

The only exception is plate C11R1 in batch C, which only has one plate.

02B CASEU sanger sequencing

[1] "caseu_calibration.Rmd" "caseu_genewiz.pdf"     "caseu_genewiz.Rmd"     "caseu_pcr.pdf"        
[5] "caseu_pcr.Rmd"         "caseu_protocol.pdf"    "caseu_protocol.Rmd"   
devtools::install_bitbucket('dattamanoshi/caseu') # Install CASEU package
library(CASEU)

Test on example data

Test the example code and data.

Fit Sanger sequences of a mixed culture of four strains. This step may take a few seconds.

library(CASEU)
data('fourStrainExpt') # load an example dataset
results <-
  fitSangerMixture(mixture=fourStrainExpt$mixture, # mixture
  components = fourStrainExpt$components, # Four individual 16S sequences
  verbose=TRUE)

save(results, file = here::here("data/temp/CASEU_test_results1.Rdata"))

Fitted mixture sanger electropherogram output

CASEU pilot1

The plate layout of PCR plate and list of samples are specified in output/protocol/protocol_20190813_Sanger_seq_prep.pdf.

The isolates used in this round is from the list below.

isolates
Isolate Code Taxa
C11R1 isolate 1 A Pseudomonas
C1R7 isolate 2 B Pseudomonas
C1R7 isolate 1 C Enterobacter
C1R7 isolate 7 D Raoultella

Read trace matrices for isolates and mixtures

Rows: 16 Columns: 8
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): MixtureName, Treatment, Isolate1, Isolate2
dbl (4): Isolate1Freq, Isolate2Freq, Isolate1FreqPredicted, Isolate2FreqPredicted

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Plot the expected isolate frequency vs. CASEU predicted frequency

Rows: 16 Columns: 8
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): MixtureName, Treatment, Isolate1, Isolate2
dbl (4): Isolate1Freq, Isolate2Freq, Isolate1FreqPredicted, Isolate2FreqPredicted

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Saving 7.5 x 7.5 in image

CASEU pilot2

The plate layout of PCR plate and list of samples are specified in output/protocol/protocol_20190813_Sanger_seq_prep.pdf. There are 32 samples from pairwise competition and 16 samples from control. Also read Sylvie’s data.

Isolates A B C D in control are the isolates below.

Isolate Code Taxa
C11R1 isolate 1 A Pseudomonas
C1R7 isolate 2 B Pseudomonas
C1R7 isolate 1 C Enterobacter
C1R7 isolate 7 D Raoultella

Control pairs

In the 12 control synthetic pairs that were made of 4 isolates, compare these pairs’ OD frequencies, colony counts, and CASEU predictions.

Read CASEU predicted frequencies and colony count frequencies in the 12 control pairs.

Rows: 36 Columns: 9
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): MixtureName, User, Treatment, Isolate1, Isolate2
dbl (4): Isolate1Freq, Isolate2Freq, Isolate1FreqPredicted, Isolate2FreqPredicted

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 12 Columns: 10
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): MixtureName, User, Treatment, Isolate1, Isolate2
dbl (5): Isolate1Freq, Isolate2Freq, Isolate1Colony, Isolate2Colony, Dilution

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Join the CASEU predicted result of control pairs in CASEU_pilot2 with the plating result in CASEU_pilot2_plating. The pair CYC_control_50_50_CD has a lot colonies and the colony count of C is just approximation (n=300)

Plot the CASEU predictio vs. colony counts and CASEU prediction vs. OD frequencies

CASEU pilot3

The plate layout of PCR plate and list of samples are specified in output/protocol/protocol_20190923_SequalPrep_Sanger_prep.pdf.

Read trace matrices for isolates and mixtures

Rows: 42 Columns: 9
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): MixtureName, Community
dbl (7): Isolate1Freq, Isolate2Freq, Isolate1, Isolate2, Isolate1FreqPredicted, Isolate2FreqPredict...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

CASEU pilot4

The plate layout of PCR plate and list of samples are specified in output/protocol/protocol_20191007_Sanger_seq_prep.pdf.

Read trace matrices for isolates and mixtures

Rows: 30 Columns: 9
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): MixtureName, Community
dbl (7): Isolate1Freq, Isolate2Freq, Isolate1, Isolate2, Isolate1FreqPredicted, Isolate2FreqPredict...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

02C pairs_OD_CFU

General formula of error propagation

This section explains the error propagation theory to estimate the uncertainty in the experimental measurement. There are one or more quantities \(x, y, ...\), with corresponding uncertainties \(\delta x, \delta y, ...\) and that we wish to use the measured values of x and y to calculate the quantity of real interest q. There are three provisional rules:

  1. The square-root rule for counting experiments. The average number of event in time T is \(v\pm\sqrt{v}\)

  2. Uncertainty in sums and differences. The computed mean value \(q=x+y+z-(u+w)\). If the uncertainties in x, …, w are known to be independent and random, then the uncertainty in the computed value of q is the quadratic sum \(\delta q = \sqrt{(\delta x)^2+(\delta y)^2+(\delta z)^2+(\delta u)^2+(\delta w)^2}\) , In any case, \(\delta q\) is never larger than their ordinary sum \(\delta q \leqslant \delta x + \delta y+ \delta z + \delta u + \delta w\)

  3. Uncertainty in product and quotients. \(q=\frac{x\times z}{u\times w}\), then the fractional uncertainty in the computed value q is the sum. If the uncertainties in x, …,w are independent and random, then the fractional uncertainty in q is the sum in quadrature of the original uncertainties, \(\frac{\delta q}{\left|q\right|} = \sqrt{(\frac{\delta x}{\left|x\right|})^2 + \frac{\delta y}{\left|y\right|})^2 +\frac{\delta z}{\left|z\right|})^2 +\frac{\delta u}{\left|u\right|})^2 + \frac{\delta w}{\left|w\right|})^2}\). \(\frac{\delta q}{\left| q \right|} \leqslant \frac{\delta x}{\left| x \right|} + \frac{\delta z}{\left| z \right|} + \frac{\delta u}{\left| u \right|} + \frac{\delta w}{\left| w \right|}\)

Taking these three provisional rules together, the general formula for error propagation takes the following form. Assume the computed quantity is a function of \(x_1, x_2, ..., x_n\), the uncertainty in q is \[\delta q= \sqrt{(\sum{\frac{\partial q}{\partial x_i}}\delta x_i)^2}\]

Uncertainty in epsilon

The uncertainties in each isolate’ epsilon \(\epsilon_A = \frac{OD_A DF_A v_A}{CFU_A}\) comes from four parts:

  1. \(DF\): Dilution factors. The uncertainty comes from the pipetting in serial dilution, which is calcaulted below.
  2. \(v\): Plating volumes. The systematic error for P20 set at 20 uL is 0.4 uL.
  3. \(CFU\): CFU counts. The uncertainty in CFU follows poisson distribution, which means that the variance is the same as the mean (measured CFU). The standard deviation is \(\sqrt{CFU}\).
  4. \(OD\): OD measurement. The uncertainty in measuring OD in plate reader, which is assumed to be 0.001.

Dilution factor

The uncertainty in dilution factor comes from the pipetting steps in serial dilution, which include two pipetting volumes:

  1. V1: serial dispensing 10 uL of diluted solution using mP20. It has uncertainty ErrorV1 2 uL.
  2. V2: dispense 90 uL of PBS using mP200. It has uncertainty ErrorV2 0.4 uL.

For dilution factor \(10^{n}\), it has the the mean \((\frac{V_1}{V_1+V_2})^n\). To obtain the uncertainty in the measured mean, first we caluculate the partial derivatives \(\frac{\partial DF}{\partial V_1}\) and \(\frac{\partial DF}{\partial V_2}\). Then the uncertainty \(\delta DF = \sqrt{(\frac{\partial DF}{\partial V_1}\delta V_1)^2 + (\frac{\partial DF}{\partial V_2}\delta V_2)^2}\)

By using error propagation theroy, the uncertainty in isolates epsilon has the form

\[\delta \epsilon = \sqrt{(\frac{\partial \epsilon}{\partial DF}\delta DF)^2 +(\frac{\partial \epsilon}{\partial CFU}\delta CFU)^2 + (\frac{\partial \epsilon}{\partial OD}\delta OD)^2 + (\frac{\partial \epsilon}{\partial V}\delta V)^2}\]

Rows: 68 Columns: 19
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (1): Community
dbl (18): Isolate, OD620, ColonyCount, DilutionFactor, CFU, OD, V, ErrorCFU, ErrorOD, ErrorV, DF, E...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

There are 7 isolates that have either 0 CFU or negative OD value, so they don’t have epsilon values.

Convert T0 OD frequencies to CFU frequencies

The outcome of pairwise competition were determined by comparing the frequency changes between T0 and T8. The T8 frequencies were determined by plating the mature media on rich agar media on which the colonies were counted, whereas T0 frequencies were set to 95/5, 50/50 and 5/95 by mixing two isolate inocula with equal OD. In this section, I will use the OD-CFU conversion coefficient \(\epsilon\) derived from T8 isolate data to convert T0 OD frequencies into CFU frequencies. In specific, the CFU frequency of isolate 1 \(f^C_1\) of a pair can be derived from OD frequencies of isolate 1 and 2 \(f^O_1 ,f^O_2\), which have the relationship below.

\(f^C_1 = \frac{f^o_1\epsilon_1DFv}{f^o_1\epsilon_1DFv + f^o_2\epsilon_2DFv}=\frac{f^o_1\epsilon_1}{f^o_1\epsilon_1 + f^o_2\epsilon_2}\)

where \(\epsilon\) of each isolate was pre-calculated from T8 dataset. DF and v are the same in conversion.

Rows: 1116 Columns: 7
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Community, Time
dbl (5): Isolate1, Isolate2, Isolate1Freq, Isolate2Freq, Isolate1CFUFreq

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Uncertainty in T0 CFU frequencies

Write CFU frequencies to data/temp/pairs_CFU_freq_uncertainty.csv

Rows: 1116 Columns: 10
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Community, Time, RawDataType
dbl (6): Isolate1, Isolate2, Isolate1Freq, Isolate2Freq, Isolate1CFUFreq, ErrorIsolate1CFUFreq
lgl (1): Contamination

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

02D determine pairwise interaction

Combine outcomes of pairwise competition from CFU counts and CASEU

Raw data (e.g., CFU counts and CASEU Sanger sequences) are processed and generated into temporary result csv:

  1. 02B-CASEU_sanger_seq reads CASEU raw data and outputs temp/CASEU_pilot2.csv and temp/CASEU_pilot3.csv. Both files are CASEU predicted T8 frequencies.

  2. 02C-pairs_OD_CFU reads pair_competition and dilution factor data, and it outputs temp/pairs_CFU_freq_uncertainty.csv, which has the T0 OD-converted CFU frequencies and T8 CFU frequencies with uncertainties.

Note that if a pair has both CFU and CASEU result, CASEU will overwrite the CFU result

The script in this section returns a data.frame pairs_freq that has the following variables:

  • Community
  • Isolate1 and Isolate2: indices of isolates within a community. The number of isolate1 is always smaller than isolate2
  • Isolate1InitialODFreq and Isolate2InitialODFreq: 5, 50 or 95. The initial OD frequencies of isolates at T0. This two serve as discrete grouping variables.
  • Time: T0 or T8.
  • Isolate1MeasuredFreq: the measured frequency od isolate1 in the pair.
  • ErrorIsolate1MeasuredFreq: the uncertainty of Isolate1MeasuredFreq.
  • RawDataType: OD, ODtoCFU, CFU, Sanger (CASEU). The raw data type in which the isolate frequencies were measured.
  • Contamination: logical. There are contaminations in three pairs at T8 plates.

186x3x2=1116 pair-freq at two time points

Rows: 1116 Columns: 10
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Community, Time, RawDataType
dbl (6): Isolate1, Isolate2, Isolate1InitialODFreq, Isolate2InitialODFreq, Isolate1MeasuredFreq, Er...
lgl (1): Contamination

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

There is one pair-freq that cannot be specified because of contamination.

Determine pairwise interactions

Plot frequency changes. Output figure of CFU frequency changes to output/figure/pairs_freq_change_uncertainty.pdf

Table of all 27 possible combinations of fitness function and their interaction types

Rows: 27 Columns: 6
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): InteractionType, InteractionTypeFiner, FreqFunc
dbl (3): FromRare, FromMedium, FromAbundant

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Table of interaction types

Rows: 186 Columns: 13
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): Community, FreqFunc, PairIsolate1MeasuredFreqT8, InteractionType, InteractionTypeFiner
dbl (7): Isolate1, Isolate2, FromRare, FromMedium, FromAbundant, From, To
lgl (1): Isolate1Win

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Interaction table

Rows: 32 Columns: 5
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): FromRare, FromMedium, FromAbundant, InteractionType
dbl (1): Count

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Isolate tournament

Tournament ranks of each isolate. Note that I consider neturality and bistability as draw in the tournament.

  • Score: the competitive scores of isolate. This score is computed by the formula: number of wins - number of loses + 0 * number of draws.
  • Game: number of pairwise competition the isolate has played. The number of games an isolate plated within a community should be community size minus one.
  • Rank: the ranks based on Score. The ranks range from 1 to the focal community size. Isolates with the same scores in a community are given the same rank.
  • PlotRank: continuous rank for plotting convenience.

02E competition phylogeny

Isolates’ RDP taxonomy

Rows: 186 Columns: 11
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (7): Community, Family1, Family2, Genus1, Genus2, PairFermenter, PairFamily
dbl (2): Isolate1, Isolate2
lgl (2): Fermenter1, Fermenter2

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Isolates’ 16S sequence difference

Rows: 186 Columns: 5
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (4): Isolate1, Isolate2, SeqDifference, SeqLength

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Isolates’ branch distances on phylogenetic tree (deprecated)

Rows: 186 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (2): Isolate1, Isolate2
lgl (1): PairTreeDistance

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Summary

Read and combine pairs data

186 pairs

Rows: 186 Columns: 17
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (9): Community, InteractionType, InteractionTypeFiner, Family1, Family2, Genus1, Genus2, PairFe...
dbl (6): Isolate1, Isolate2, From, To, SeqDifference, SeqLength
lgl (2): Fermenter1, Fermenter2

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Pairs data.frame melted by T0/T8 and three initial frequencies. 186x3x2=1116

Rows: 1116 Columns: 20
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (9): Community, Time, RawDataType, Family1, Family2, Genus1, Genus2, PairFermenter, PairFamily
dbl (8): Isolate1, Isolate2, Isolate1InitialODFreq, Isolate2InitialODFreq, Isolate1MeasuredFreq, Er...
lgl (3): Contamination, Fermenter1, Fermenter2

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Plot outcomes types

Four example outcomes: bistability, coexistence, exclusion, and neutrality

Rows: 3 Columns: 7
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Community, InteractionType, InteractionTypeFiner
dbl (4): Isolate1, Isolate2, From, To

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.

Four example outcomes: bistability, coexistence, exclusion, and neutrality

Rows: 5 Columns: 7
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Community, InteractionType, InteractionTypeFiner
dbl (4): Isolate1, Isolate2, From, To

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
`summarise()` has grouped output by 'InteractionTypeFiner'. You can override using the `.groups` argument.

Pairs taxonomy vs. outcome of pairwise competition

`summarise()` has grouped output by 'PairFermenter'. You can override using the `.groups` argument.
`summarise()` has grouped output by 'PairFamily'. You can override using the `.groups` argument.
`summarise()` has grouped output by 'SeqDifference'. You can override using the `.groups` argument.

RDP taxonomy

Fermenter vs. Interaction type

Family vs. Interaction type

Pairwise 16S differences

Pairwise 16S differences

Coarsed-grained 16S sequence difference

Relative abundance within pairs

Relative abundance of fermenter vs. non-fermenter pairs

`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 1 rows containing non-finite values (stat_bin).

Relative abundance of Enterobacteriaceae and Pseudomonadaceae pairs

`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 1 rows containing non-finite values (stat_bin).

Fraction of pairwise coexistence within community

`summarise()` has grouped output by 'Community'. You can override using the `.groups` argument.

Fraction of coexistence in 13 communities

Error in grDevices::pdf(file = filename, ..., version = version) : 
  cannot open file '/Users/chang-yu/Desktop/Lab/invasion-network/output/figure/communities_fraction_coexistence.pdf'

Community hierarchy in communities

From Higgins2017, the competitive score \(s_i\) of each strain \(i\) was defined as its mean fraction \(f_{ij}\) after co-culture with each of the \(n-1\) competitor strains:

\[s_i=(\sum_{i\neq j}f_{ij})/(n-1)\]

The hierarchy score \(h\) for an n-member netowkr is calculated as:

\[h = \sum_{s_i>s_j}f_{ij}\]

Error: `data` must be a data frame, or other object coercible by `fortify()`, not a character vector.
Run `rlang::last_error()` to see where the error occurred.

Growth traits vs coexistence (Deprecated)

LS0tCnRpdGxlOiAiQW5hbHlzaXMgb24gcGFpcndpc2UgY29tcGV0aXRpb24gYXNzYXlzIgphdXRob3I6ICJDaGFuZy1ZdSBDaGFuZyIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGfQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGUgPSBGQUxTRSwgZWNobyA9IEZBTFNFKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGNvd3Bsb3QpCnJ1bl9zY3JpcHRzIDwtIEYKY29tbXVuaXRpZXMgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvY29tbXVuaXRpZXMuY3N2IikpCmBgYAoKCiMgR29hbAoKLSBDb21iaW5lIGFuZCByZWFkIGRhdGEgY3N2IGZyb20gMDJBIHRvIDAyRAoKLSBNYXRjaCBhbmQgY29tcGFyZSBpc29sYXRlcycgaW5mb3JtYXRpb24gdG8gb3V0Y29tZSBvZiBwYWlyd2lzZSBjb21wZXRpdGlvbgogICAgLSBSRFAgdGF4b25vbXkgKGUuZy4sIGZhbWlseSBhbmQgZ2VudXMpCiAgICAtIDE2UyBkaWZmZXJlbmNlcwogICAgLSBEaXN0YW5jZSBvbiBwaHlsb2dlbmV0aWMgdHJlZQogICAgLSBNb25vY3VsdHVyZSBncm93dGggcmF0ZSAKCi0gVGhlIFIgc2NyaXB0cyAoc291cmNlZCBpbiB0aGlzIFJtZCkgY2FuIGJlIHJ1biBleHRlcm5hbGx5IHRvIFJzdHVkaW8uCi0gVGhlIFIgc2NyaXB0cyBhcmUgb25seSBmb3Igc2F2aW5nIFIgZnVuY3Rpb25zLCBwcm9jZXNzaW5nIHJhdyBhbmQgdGVtcG9yYXJ5IGRhdGEuCi0gQWxsIHZpc3VhbGl6YXRpb24gY29kZXMgYXJlIGluIHRoaXMgUm1kIGZpbGUuCgojIDAyQSBwYWlycyBleHBlcmltZW50cwoKLSBFeHBlcmltZW50IHJlbGF0ZWQgc2NyaXB0cwoKLSBSZWFkIHBhaXJ3aXNlIGNvbXBldGl0aW9uIG91dGNvbWVzIHRoYXQgYXJlIGRldGVybWluZWQgYnkgY29sb255IGNvdW50cyBvbiBwbGF0ZXMuIAoKLSBGaWx0ZXIgb3V0IGFtYmlndW91cyBwYWlycyBhbmQgbGF0ZXIgZmlsbCBpbiB0aGUgZGF0YSBob2xlIGJ5IENBU0VVIHJlc3VsdHMuIAoKLSBNYXAgcGFpcnMgYW5kIGlzb2xhdGVzIHRvIHRoZSA5Ni13ZWxsIHBsYXRlIGxheW91dAoKCiMjIFJlYWQgdGhlIHBhaXJ3aXNlIGNvbXBldGl0aXZlIG91dGNvbWVzIGRldGVybWluZWQgYnkgY29sb255IGNvdW50aW5nIG9uIFRTQQoKR2VuZXJhdGUgdGFibGUgZm9yIG1hbnVhbCBrZXktaW4KCmBgYHtyIGV2YWwgPSBGfQppZiAoRkFMU0UpIHNvdXJjZSgic2NyaXB0LzAyQS1wYWlyc19leHBlcmltZW50LTAxLXBhaXJ3aXNlX21hbnVhbF9rZXlfaW4uUiIpCmBgYAoKVGhlbiBJIG1hbnVhbGx5IGNoZWNrZWQgdGhlIHNjYW5uZWQgcGxhdGUgaW1hZ2VzIG9mIGNvbXBldGl0aXZlIHBhaXJzLiBUaGUgcGxhdGUgaW1hZ2VzIGFyZSBzYXZlZCBpbiBmb2xkZXIgYHBsYXRlX3NjYW4vaGlnaF9vcmRlcl9wbGF0ZV9zY2FuL2AgYW5kIGRpdmlkZWQgYWNjb3JkaW5nIHRoZSBleHBlcmltZW50YWwgYmF0Y2hlcy4KCkJhdGNoIHwgQ29tbXVuaXR5Ci0tLS0tLXwtLS0tLS0tLS0tLQpCMiAgICB8IDIuNiwgMi44LCA3LjEsIDguNCwgMTAuMiwgMTEuMQpDICAgICB8IDExLjEgaXNvbGF0ZSAxCkMyICAgIHwgMTEuMgpEICAgICB8IDEuMiwgMS40LCAxLjYsIDEuNywgNC4xLCAxMS41CgoKYGBge3Igd2FybmluZyA9IEZ9CiMgUmVhZCByZXN1bHQgY29sb255IGNvdW50cyBhbmQgZGlsdXRpb24gZmFjdG9yCmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJBLXBhaXJzX2V4cGVyaW1lbnQtMDItY29sb255X2NvdW50LlIiKQpgYGAKClRoZXJlIGFyZSAxODZ4Mz01NTggb3V0Y29tZXMgb2YgcGFpcndpc2UgY29tcGV0aXRpb25zLgoKYGBge3J9CnBhaXJzX2NvbXBldGl0aW9uIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wYWlyc19jb21wZXRpdGlvbi5jc3YiKSkKcGFpcnNfY29tcGV0aXRpb24KYGBgCgo2NyBwYWlycyB3aXRob3V0IGRldGVybWluZWQgb3V0Y29tZXMgb2YgcGFpcndpc2UgY29tcGV0aXRpb25zIHdpbGwgYmUgZGV0ZXJtaW5lZCBieSB1c2luZyBDQVNFVSBtZXRob2QKCmBgYHtyfQpwYWlyc19jb21wZXRpdGlvbiAlPiUKICBmaWx0ZXIoaXMubmEoQ29sb255Q291bnQpKQpgYGAKCjE4NiBwYWlyIElEcyBzYXZlZCBpbiBgcGFpcnNfSURgCgpgYGB7cn0KcGFpcnNfSUQgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL3BhaXJzX0lELmNzdiIpKQpwYWlyc19JRApgYGAKCgoKIyMgQW1iaWd1b3VzIHBhaXJzIGFuZCBpc29sYXRlcyBvbiBUU0EgYWdhciBwbGF0ZXMKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQS1wYWlyc19leHBlcmltZW50LTAzLXBhaXJ3aXNlX2FtYmlndW91cy5SIikKYGBgCgpUaGVyZSBhcmUgNjcgcGFpci1mcmVxcyB0aGF0IEkgZG9uJ3Qga25vdyB0aGUgY29tcGV0aXRpdmUgb3V0Y29tZXMgYnkgVFNBIHBsYXRlIGNvdW50aW5nLiBUaGUgYW1iaWd1b3VzIHBhaXJzIHdpbGwgYmUgbGF0ZXIgZXhhbWluZWQgYnkgdXNpbmcgc2VsZWN0aXZlIG1lZGlhIG9yIFNhbmdlciBzZXF1ZW5jaW5nLiAKCmBgYHtyfQpwYWlyc19hbWJpZ3VvdXMgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL3BhaXJzX2FtYmlndW91cy5jc3YiKSkKcGFpcnNfYW1iaWd1b3VzCmBgYAoKMjggcGFpcnMKCmBgYHtyfQpwYWlyc19hbWJpZ3VvdXMgJT4lIAogIGdyb3VwX2J5KENvbW11bml0eSwgSXNvbGF0ZTEsIElzb2xhdGUyKSAlPiUKICBzdW1tYXJpemUoQ291bnQgPSBuKCkpCmBgYAoKMzYgaXNvbGF0ZXMgaW52b2x2ZWQgaW4gdGhlIGFtYmlndW91cyBwYWlycy4gCgpgYGB7cn0KaXNvbGF0ZXNfYW1iaWd1b3VzIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9pc29sYXRlc19hbWJpZ3VvdXMuY3N2IikpCmlzb2xhdGVzX2FtYmlndW91cwpgYGAKCgoKIyMgTWFwIHBhaXJzIGFuZCBpc29sYXRlcyB0byB0aGUgRFc5NiBwbGF0ZSBsYXlvdXQKCmBgYHtyIHdhcm5pbmcgPSBGfQpwbGF0ZXNfbmFtZSA8LSBjKCJwbGF0ZV9CMl85MzMiLCAicGxhdGVfQjJfNDQ0IiwgInBsYXRlX0NfQzExUjEiLCAicGxhdGVfQzJfMTNBIiwgInBsYXRlX0MyXzEzQiIsICJwbGF0ZV9EXzc1IiwgInBsYXRlX0RfNTU0MyIpCnNvdXJjZSgic2NyaXB0LzAyQS1wYWlyc19leHBlcmltZW50LTA0LXBhaXJ3aXNlX3BsYXRlX2xheW91dC5SIikKYGBgCgpFYWNoIHBsYXRlIGhhcyA5NiByb3dzIGFuZCBoYXMgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXMKCmBgYHtyfQpwbGF0ZXMgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvcGxhdGVzLmNzdiIpKQpzdHIocGxhdGVzKQpgYGAKClJlYWQgcGxhdGUgbGF5b3V0IGJ5IGJhdGNoCgpgYGB7cn0KZHJhd19wbGF0ZV9mcm9tX2RmIDwtIGZ1bmN0aW9uKAogIGRmLAogIHdlbGxfc2l6ZSA9IDUsCiAgdGV4dF9zaXplID0gMywKICBhbm5vdGF0aW9uID0gVFJVRSwKICBhbm5vdGF0ZV9lYWNoX3dlbGwgPSBUUlVFLAogIGZpbGxfbGVnZW5kID0gRiwKICB2anVzdCA9IDAsCiAgLi4uCikgewogICMgQ2hlY2sKICBzdG9waWZub3QoCiAgICBpcy5kYXRhLmZyYW1lKGRmKSwKICAgICJXZWxsIiAlaW4lIG5hbWVzKGRmKSwKICAgICJUZXh0TGFiZWwiICVpbiUgbmFtZXMoZGYpIHwgIkZpbGxMYWJlbCIgJWluJSBuYW1lcyhkZikKICApCgogICMgTWFrZSBwbGF0ZQogIHBsYXRlIDwtIGRmICU+JQogICAgbXV0YXRlKAogICAgICBSb3cgPSBtYXRjaChzdWJzdHIoV2VsbCwgMSwgMSksIExFVFRFUlNbMTo4XSksCiAgICAgIENvbCA9IHN1YnN0cihXZWxsLCAyLCAzKSAlPiUgYXMubnVtZXJpYygpLAogICAgKSAlPiUKICAgIGZpbHRlcighZ3JlcGwoImJsYW5rIiwgLiRGaWxsTGFiZWwpKSAlPiUKICAgIG11dGF0ZShGaWxsTGFiZWwgPSBhcy5jaGFyYWN0ZXIoRmlsbExhYmVsKSkKCiAgIyBFbXB0eSB3ZWxsCiAgZW1wdHlfd2VsbCA8LSBkYXRhLmZyYW1lKAogICAgUm93ID0gcmVwKDE6OCwgZWFjaCA9IDEyKSwKICAgIENvbCA9IHJlcCgxOjEyLCA4KQogICkKCiAgIyBQbG90IGJsYW5rIHBsYXRlCiAgaWYgKGFsbChpcy5uYShwbGF0ZSRGaWxsTGFiZWwpKSkgewogICAgcmV0dXJuKAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gZW1wdHlfd2VsbCwgYWVzKHggPSBDb2wsIHkgPSBSb3cpLCBzaGFwZSA9IDEsIHNpemUgPSB3ZWxsX3NpemUsIGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BKSArCiAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAiIiwgYnJlYWtzID0gMToxMiwgbGFiZWxzID0gMToxMiwgbGltaXRzID0gYygxLCAxMiksIHBvc2l0aW9uID0gInRvcCIpICsKICAgICAgICBzY2FsZV95X3JldmVyc2UobmFtZSA9ICIiLCBsaW0gPSBjKDgsIDEpLCBicmVha3MgPSAxOjgsIGxhYmVscyA9IExFVFRFUlNbMTo4XSkgKwogICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgIE5VTEwKICAgICkKICB9CgogICMgUGxvdCBzZWdtZW50cwogIGdfZW1wdHlfd2VsbCA8LSBnZW9tX3BvaW50KGRhdGEgPSBlbXB0eV93ZWxsLCBhZXMoeCA9IENvbCwgeSA9IFJvdyksCiAgICBzaGFwZSA9IDEsIHNpemUgPSB3ZWxsX3NpemUsIGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BKQoKICBnX3BsYXRlIDwtIGdlb21fcG9pbnQoZGF0YSA9IHBsYXRlLCBhZXMoeCA9IENvbCwgeSA9IFJvdywgZmlsbCA9IEZpbGxMYWJlbCksCiAgICBwY2ggPSAyMSwgc2l6ZSA9IHdlbGxfc2l6ZSkKCgogICMgQW5ub3RhdGUgdGV4dCBmb3IgZmlsbAogIHBsYXRlX2ZpbGxfdGV4dCA8LSBwbGF0ZSAlPiUKICAgIGdyb3VwX2J5KEZpbGxMYWJlbCkgJT4lCiAgICBzdW1tYXJpemUoQ29sID0gbWVhbihDb2wpLCBSb3cgPSBtZWFuKFJvdykpICU+JQogICAgbXV0YXRlKFJvdyA9IGlmZWxzZSgoUm93ICUlIDEpID09IDAsIFJvdyAtIHZqdXN0LCBSb3cpKQoKICBpZiAoIlRleHRMYWJlbCIgJWluJSBuYW1lcyhkZikpIHsKICAgIGdfdGV4dF9sYWJlbCA8LSBnZW9tX3RleHQoZGF0YSA9IHBsYXRlLCBhZXMoeCA9IENvbCwgeSA9IFJvdywgbGFiZWwgPSBUZXh0TGFiZWwpLCBzaXplID0gdGV4dF9zaXplKQogIH0gZWxzZSBnX3RleHRfbGFiZWwgPC0gTlVMTAoKICBpZiAoYW5ub3RhdGlvbiA9PSBUKSB7CiAgICBnX3RleHRfZmlsbCA8LSBnZW9tX3RleHQoZGF0YSA9IHBsYXRlX2ZpbGxfdGV4dCwgYWVzKHggPSBDb2wsIHkgPSBSb3csIGxhYmVsID0gRmlsbExhYmVsKSkKICB9IGVsc2UgZ190ZXh0X2ZpbGwgPC0gTlVMTAoKCiAgIyBQbG90IHBsYXRlCiAgcHAgPC0KICAgIGdncGxvdCgpICsgZ19wbGF0ZSArIGdfZW1wdHlfd2VsbCArIGdfdGV4dF9sYWJlbCArIGdfdGV4dF9maWxsICsKICAgIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIiIsIGJyZWFrcyA9IDE6MTIsIGxhYmVscyA9IDE6MTIsIGxpbWl0cyA9IGMoMSwgMTIpLCBwb3NpdGlvbiA9ICJ0b3AiKSArCiAgICBzY2FsZV95X3JldmVyc2UobmFtZSA9ICIiLCBsaW0gPSBjKDgsIDEpLCBicmVha3MgPSAxOjgsIGxhYmVscyA9IExFVFRFUlNbMTo4XSkgKwogICAgdGhlbWVfYncoKSArCiAgICBOVUxMCgogIGlmIChmaWxsX2xlZ2VuZCA9PSBUKSB7CiAgICByZXR1cm4ocHArdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpKQogIH0gZWxzZSByZXR1cm4ocHAgKyBndWlkZXMoZmlsbD1GKSkKCn0KCmVhc3lfcGxvdF9wbGF0ZSA8LSBmdW5jdGlvbihwbGF0ZSkgewogIG11dGF0ZShwbGF0ZSwKICAgIFRleHRMYWJlbCA9IGlmZWxzZShNaXhJc29sYXRlLCBwYXN0ZShJc29sYXRlMSwgSXNvbGF0ZTIsIHNlcCA9ICJfIiksIElzb2xhdGUxKSwKICAgIEZpbGxMYWJlbCA9IHBhc3RlMChDb21tdW5pdHksIGlmZWxzZShNaXhJc29sYXRlLCAiIiwgIl9zaW5nbGUiKSkpICU+JQogICAgZHJhd19wbGF0ZV9mcm9tX2RmKCkKfQoKYGBgCgpgYGB7cn0KZm9yIChpIGluIDE6NykgYXNzaWduKHBhc3RlMCgicCIsIGkpLCBlYXN5X3Bsb3RfcGxhdGUoZXZhbChwYXJzZSh0ZXh0ID0gcGxhdGVzX25hbWVbaV0pKSkpCnAgPC0gcGxvdF9ncmlkKHAxLCBwMiwgcDMsIE5VTEwsIHA0LCBwNSwgcDYsIHA3LCBsYWJlbHMgPSBjKCJCMl85MzMiLCAiQjJfNDQ0IiwgIkNfQzExUjEiLCAiIiwgIkMyXzEzQSIsICJDMl8xM0IiLCAiRF83NSIsICJEXzU1NDMiKSwgbmNvbCA9IDIsIG5yb3cgPSA0KQpnZ3NhdmUoImZpZ3VyZS8wMkEtcGxhdGVfbGF5b3V0LnBkZiIsIHAsIHdpZHRoID0gMTIsIGhlaWdodCA9IDE2KQpgYGAKClBsYXRlIGxheW91dCB0aGF0IHRha2VzIGRpZmZlcmVudCBpbml0aWFsIGZyZXF1ZW5jaWVzOgoKLSBQMSBpcyA1MCU6NTAlLgoKLSBQMiBhbmQgUDMgYXJlIGlkZW50aWNhbCBhbmQgd2hvc2Ugcm93cyBhcmUgOTUlIGFuZCBjb2x1bW5zIGFyZSA1JS4KClRoZSBvbmx5IGV4Y2VwdGlvbiBpcyBwbGF0ZSBDMTFSMSBpbiBiYXRjaCBDLCB3aGljaCBvbmx5IGhhcyBvbmUgcGxhdGUuCgoKIyAwMkIgQ0FTRVUgc2FuZ2VyIHNlcXVlbmNpbmcKCi0gVG8gZGV0ZXJtaW5lIHRoZSByZWxhdGl2ZSBhYnVuZGFuY2Ugb2Ygb2YgYW1iaWd1b3VzIHBhaXJzIGluIGNvbXBldGl0aXZlIGFzc2F5cy4gCgotIFVzZSBDQVNFVSBwYWNrYWdlcyB0byBhbmFseXNlIHRoZSBTYW5nZXIgc2VxdWVuY2luZyBvZiBtaXh0dXJlIGN1bHR1cmUuCgotIFNhbmdlciBzZXF1ZW5jaW5nIHByb3RvY29sIHByZXBhcmF0aW9uLiBFeHBlcmltZW50YWwgcHJvdG9jb2wgZmlsZXMgYXJlIHNhdmVkIGluIGZvbGRlciBgb3V0cHV0L3Byb3RvY29sL2AKCmBgYHtyfQpsaXN0LmZpbGVzKGhlcmU6OmhlcmUoIm91dHB1dC9wcm90b2NvbCIpLCBwYXR0ZXJuID0gImNhc2V1IikKYGBgCgotIE9uY2Ugd2UgZ290IHRoZSBtaXh0dXJlIFNhbmdlciBzZXF1ZW5jZXMgYmFjaywgd2UgaW1wbGVtZW50IGFuYWx5c2lzIGJ5IHVzaW5nIGBDQVNFVWAgKENvbXBvc2l0aW9uYWwgYW5hbHlzaXMgYnkgU2FuZ2VyIGVsZWN0cm9waGVyb2dyYW0gdW5taXhpbmcpLCBhbiBSIHBhY2thZ2UgZGVzaWduZWQgZm9yIHF1YW50aWZ5aW5nIHJlbGF0aXZlIGFidW5kYW5jZSBvZiBTYW5nZXIgc2VxdWVuY2VzIG1peHR1cmUuIFtzb3VyY2UgY29kZV0oaHR0cHM6Ly9iaXRidWNrZXQub3JnL0RhdHRhTWFub3NoaS9jYXNldSkuIEluc3RhbGwgYENBU0VVYCBmcm9tIGJpdGJ1Y2tldC4KCi0gQ2hlY2sgb3V0IFtwYWNrYWdlIHZpZ25ldHRlXShodHRwczovL2h0bWxwcmV2aWV3LmdpdGh1Yi5pby8/aHR0cHM6Ly9iaXRidWNrZXQub3JnL2RhdHRhbWFub3NoaS9jYXNldS9yYXcvbWFzdGVyL2RvYy9DQVNFVV9WaWduZXR0ZS5odG1sKS4KCmBgYHtyLCBlY2hvID0gVFJVRSwgZXZhbCA9IEZBTFNFfQpkZXZ0b29sczo6aW5zdGFsbF9iaXRidWNrZXQoJ2RhdHRhbWFub3NoaS9jYXNldScpICMgSW5zdGFsbCBDQVNFVSBwYWNrYWdlCmxpYnJhcnkoQ0FTRVUpCmBgYAoKCiMjIFRlc3Qgb24gZXhhbXBsZSBkYXRhCgpUZXN0IHRoZSBleGFtcGxlIGNvZGUgYW5kIGRhdGEuCgpGaXQgU2FuZ2VyIHNlcXVlbmNlcyBvZiBhIG1peGVkIGN1bHR1cmUgb2YgZm91ciBzdHJhaW5zLiBUaGlzIHN0ZXAgbWF5IHRha2UgYSBmZXcgc2Vjb25kcy4KCmBgYHtyIGVjaG8gPSBULCBldmFsID0gRn0KbGlicmFyeShDQVNFVSkKZGF0YSgnZm91clN0cmFpbkV4cHQnKSAjIGxvYWQgYW4gZXhhbXBsZSBkYXRhc2V0CnJlc3VsdHMgPC0KICBmaXRTYW5nZXJNaXh0dXJlKG1peHR1cmU9Zm91clN0cmFpbkV4cHQkbWl4dHVyZSwgIyBtaXh0dXJlCiAgY29tcG9uZW50cyA9IGZvdXJTdHJhaW5FeHB0JGNvbXBvbmVudHMsICMgRm91ciBpbmRpdmlkdWFsIDE2UyBzZXF1ZW5jZXMKICB2ZXJib3NlPVRSVUUpCgpzYXZlKHJlc3VsdHMsIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhL3RlbXAvQ0FTRVVfdGVzdF9yZXN1bHRzMS5SZGF0YSIpKQpgYGAKCmBgYHtyIGV2YWwgPSBGfQpsb2FkKGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhL3RlbXAvQ0FTRVVfdGVzdF9yZXN1bHRzMS5SZGF0YSIpKQpwcmludChyZXN1bHRzKSAgICAgICAgICAgICAgICAgICAgICAjIHZpZXcgdGhlIHJlc3VsdHMKcGxvdChyZXN1bHRzKSAgICAgICAgICAgICAgICAgICAgICAgIyBwbG90IHRoZSBmaXQKc2FuZ2VyRml0RGlhZ25vc3RpY1Bsb3QocmVzdWx0cykgICAgIyBwbG90IGEgYnVuY2ggbW9yZSBkaWFnbm9zdGljcwpgYGAKCkZpdHRlZCBtaXh0dXJlIHNhbmdlciBlbGVjdHJvcGhlcm9ncmFtIG91dHB1dAoKYGBge3IgZXZhbCA9IEZ9Cm5hbWVzKHJlc3VsdHMpCmBgYAoKCgojIyBDQVNFVSBwaWxvdDEKClRoZSBwbGF0ZSBsYXlvdXQgb2YgUENSIHBsYXRlIGFuZCBsaXN0IG9mIHNhbXBsZXMgYXJlIHNwZWNpZmllZCBpbiBgb3V0cHV0L3Byb3RvY29sL3Byb3RvY29sXzIwMTkwODEzX1Nhbmdlcl9zZXFfcHJlcC5wZGZgLiAKCmBgYHtyfQpmcmVhZChoZXJlOjpoZXJlKCJvdXRwdXQvcHJvdG9jb2wvdGFiX2ZpZy9wcm90b2NvbF8yMDE5MDgxM19TYW5nZXJfc2VxX3ByZXAtZ2VuZXdpel90YWJsZS5jc3YiKSkKYGBgCgpUaGUgaXNvbGF0ZXMgdXNlZCBpbiB0aGlzIHJvdW5kIGlzIGZyb20gdGhlIGxpc3QgYmVsb3cuCgpJc29sYXRlICAgICAgICAgfCAgQ29kZSAgICAgfCAgVGF4YQotLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tfC0tLS0tLS0KQzExUjEgaXNvbGF0ZSAxIHwgQSAgICAgICAgIHwgUHNldWRvbW9uYXMKQzFSNyBpc29sYXRlIDIgIHwgQiAgICAgICAgIHwgUHNldWRvbW9uYXMKQzFSNyBpc29sYXRlIDEgIHwgQyAgICAgICAgIHwgRW50ZXJvYmFjdGVyCkMxUjcgaXNvbGF0ZSA3ICB8IEQgICAgICAgICB8IFJhb3VsdGVsbGEKVGFibGU6IGlzb2xhdGVzCgpSZWFkIHRyYWNlIG1hdHJpY2VzIGZvciBpc29sYXRlcyBhbmQgbWl4dHVyZXMKCmBgYHtyfQppZihydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJCLUNBU0VVX3Nhbmdlcl9zZXEtMDEtcGlsb3QxLlIiKQpgYGAKCgpgYGB7cn0KQ0FTRVVfcGlsb3QxIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9DQVNFVV9waWxvdDEuY3N2IikpCkNBU0VVX3BpbG90MQpgYGAKCgpQbG90IHRoZSBleHBlY3RlZCBpc29sYXRlIGZyZXF1ZW5jeSB2cy4gQ0FTRVUgcHJlZGljdGVkIGZyZXF1ZW5jeQoKYGBge3IgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aD0zfQpDQVNFVV9waWxvdDEgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL0NBU0VVX3BpbG90MS5jc3YiKSkKQ0FTRVVfcGlsb3QxX3AxIDwtIAogIENBU0VVX3BpbG90MSAlPiUKICBmaWx0ZXIoSXNvbGF0ZTEgIT0gIkIiLCBJc29sYXRlMiAhPSAiQiIpICU+JSAjIFdpdGhvdXQgQiBhbmQgCiAgbXV0YXRlKFRyZWF0bWVudCA9IGlmZWxzZShUcmVhdG1lbnQgPT0gIkFNIiwgImFtcGxpY29uIG1peHR1cmUiLCAiT0QgbWl4dHVyZSIpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBJc29sYXRlMUZyZXEsIHkgPSBJc29sYXRlMUZyZXFQcmVkaWN0ZWQsIGNvbG9yID0gVHJlYXRtZW50KSkgKwogIGdlb21faml0dGVyKHNpemUgPSAyKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtLjAxLCAuNikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtLjAxLCAuNikpICsKICBmYWNldF9ncmlkKElzb2xhdGUxIH4gSXNvbGF0ZTIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKwogIGxhYnMoeCA9ICJFeHBlY3RlZCBpc29sYXRlIGZyZXF1ZW5jeSIsIHkgPSAiQ0FTRVUgcHJlZGljdGVkIGlzb2xhdGUgZnJlcXVlbmN5IikKCkNBU0VVX3BpbG90MV9wMQpnZ3NhdmUoImZpZ3VyZS8wMkItQ0FTRVVfcGlsb3QxX2V4cGVjdGVkX3ZzX3ByZWRpY3RlZC5wbmciLCBDQVNFVV9waWxvdDFfcDEpCmBgYAoKCgoKIyMgQ0FTRVUgcGlsb3QyCgpUaGUgcGxhdGUgbGF5b3V0IG9mIFBDUiBwbGF0ZSBhbmQgbGlzdCBvZiBzYW1wbGVzIGFyZSBzcGVjaWZpZWQgaW4gYG91dHB1dC9wcm90b2NvbC9wcm90b2NvbF8yMDE5MDgxM19TYW5nZXJfc2VxX3ByZXAucGRmYC4gVGhlcmUgYXJlIDMyIHNhbXBsZXMgZnJvbSBwYWlyd2lzZSBjb21wZXRpdGlvbiBhbmQgMTYgc2FtcGxlcyBmcm9tIGNvbnRyb2wuIEFsc28gcmVhZCBTeWx2aWUncyBkYXRhLiAKCmBgYHtyIGluY2x1ZGUgPSBGfQpnZW5ld2l6X3BpbG90MiA8LSBmcmVhZChoZXJlOjpoZXJlKCJvdXRwdXQvcHJvdG9jb2wvdGFiX2ZpZy9wcm90b2NvbF8yMDE5MDkxMF9TYW5nZXJfc2VxX3ByZXAtZ2VuZXdpel90YWJsZV9DWUMuY3N2IikpIApnZW5ld2l6X3BpbG90MgpgYGAKCklzb2xhdGVzIEEgQiBDIEQgaW4gY29udHJvbCBhcmUgdGhlIGlzb2xhdGVzIGJlbG93LiAKCklzb2xhdGUgICAgICAgICB8ICBDb2RlICAgICB8ICBUYXhhCi0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18LS0tLS0tLQpDMTFSMSBpc29sYXRlIDEgfCBBICAgICAgICAgfCBQc2V1ZG9tb25hcwpDMVI3IGlzb2xhdGUgMiAgfCBCICAgICAgICAgfCBQc2V1ZG9tb25hcwpDMVI3IGlzb2xhdGUgMSAgfCBDICAgICAgICAgfCBFbnRlcm9iYWN0ZXIKQzFSNyBpc29sYXRlIDcgIHwgRCAgICAgICAgIHwgUmFvdWx0ZWxsYQoKYGBge3IgZXZhbCA9IEZ9CiMgRWFjaCBzY3JpcHQgdGFrZXMgfjEwIG1pbnMgdG8gcnVuCnNvdXJjZSgic2NyaXB0LzAyQi1DQVNFVV9zYW5nZXJfc2VxLTAyLXBpbG90Mi5SIikKI3NvdXJjZSgic2NyaXB0LzAyQi1DQVNFVV9zYW5nZXJfc2VxLTAzLXBpbG90Ml9TeWx2aWUuUiIpICMgUnVuIFN5bHZpZSdzIHNlcXVlbmNlCmBgYAoKCiMjIyBDb250cm9sIHBhaXJzCgpJbiB0aGUgMTIgY29udHJvbCBzeW50aGV0aWMgcGFpcnMgdGhhdCB3ZXJlIG1hZGUgb2YgNCBpc29sYXRlcywgY29tcGFyZSB0aGVzZSBwYWlycycgT0QgZnJlcXVlbmNpZXMsIGNvbG9ueSBjb3VudHMsIGFuZCBDQVNFVSBwcmVkaWN0aW9ucy4KClJlYWQgQ0FTRVUgcHJlZGljdGVkIGZyZXF1ZW5jaWVzIGFuZCBjb2xvbnkgY291bnQgZnJlcXVlbmNpZXMgaW4gdGhlIDEyIGNvbnRyb2wgcGFpcnMuCgpgYGB7cn0KIyBSZWFkIGRhdGEKQ0FTRVVfcGlsb3QyIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9DQVNFVV9waWxvdDIuY3N2IikpCkNBU0VVX3BpbG90Ml9wbGF0aW5nIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvcmF3L1Nhbmdlci9DQVNFVV9waWxvdDIvQ0FTRVVfcGlsb3QyX3BsYXRpbmcuY3N2IikpICU+JQogIG11dGF0ZShJc29sYXRlMUNvbG9ueUZyZXEgPSBJc29sYXRlMUNvbG9ueSAvIChJc29sYXRlMUNvbG9ueSArIElzb2xhdGUyQ29sb255KSwKICAgIElzb2xhdGUyQ29sb255RnJlcSA9IElzb2xhdGUyQ29sb255IC8gKElzb2xhdGUxQ29sb255ICsgSXNvbGF0ZTJDb2xvbnkpKQpgYGAKCkpvaW4gdGhlIENBU0VVIHByZWRpY3RlZCByZXN1bHQgb2YgY29udHJvbCBwYWlycyBpbiBgQ0FTRVVfcGlsb3QyYCB3aXRoIHRoZSBwbGF0aW5nIHJlc3VsdCBpbiBgQ0FTRVVfcGlsb3QyX3BsYXRpbmdgLiBUaGUgcGFpciBDWUNfY29udHJvbF81MF81MF9DRCBoYXMgYSBsb3QgY29sb25pZXMgYW5kIHRoZSBjb2xvbnkgY291bnQgb2YgQyBpcyBqdXN0IGFwcHJveGltYXRpb24gKG49MzAwKQoKYGBge3J9CkNBU0VVX3BpbG90Ml9jb250cm9sIDwtIENBU0VVX3BpbG90MiAlPiUKICBmaWx0ZXIoVHJlYXRtZW50ID09ICJjb250cm9sIikgJT4lCiAgbGVmdF9qb2luKENBU0VVX3BpbG90Ml9wbGF0aW5nLCBieSA9IGMoIk1peHR1cmVOYW1lIiwgIlVzZXIiLCAiVHJlYXRtZW50IiwgIklzb2xhdGUxRnJlcSIsICJJc29sYXRlMkZyZXEiLCAiSXNvbGF0ZTEiLCAiSXNvbGF0ZTIiKSkKYGBgCgpQbG90IHRoZSBDQVNFVSBwcmVkaWN0aW8gdnMuIGNvbG9ueSBjb3VudHMgYW5kIENBU0VVIHByZWRpY3Rpb24gdnMuIE9EIGZyZXF1ZW5jaWVzCgpgYGB7ciB3YXJuaW5nPUZ9CkNBU0VVX3BpbG90Ml9wMSA8LSAKICBDQVNFVV9waWxvdDJfY29udHJvbCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBJc29sYXRlMUNvbG9ueUZyZXEsIHkgPSBJc29sYXRlMUZyZXFQcmVkaWN0ZWQsIGNvbG9yID0gVHJlYXRtZW50KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbG9yID0gImJsYWNrIikgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC0uMDEsIDEuMDEpLCBicmVha3MgPSBjKDAsIDAuNSwgMSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtLjAxLCAxLjAxKSwgYnJlYWtzID0gYygwLCAwLjUsIDEpKSArCiAgZmFjZXRfZ3JpZChJc29sYXRlMSB+IElzb2xhdGUyKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpICsKICBsYWJzKHggPSAiRXhwZWN0ZWQgaXNvbGF0ZSBmcmVxdWVuY3kgYnkgY29sb255IGNvdW50aW5nIiwgCiAgICB5ID0gIkNBU0VVIHByZWRpY3RlZCBpc29sYXRlIGZyZXF1ZW5jeSIpICsKICBnZ3RpdGxlKCJDQVNFVSBwcmVkaWN0aW9uIHZzLiBDb2xvbnkgY291bnRzIikKCkNBU0VVX3BpbG90Ml9wMiA8LSAKICBDQVNFVV9waWxvdDJfY29udHJvbCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBJc29sYXRlMUZyZXEsIHkgPSBJc29sYXRlMUZyZXFQcmVkaWN0ZWQsIGNvbG9yID0gVHJlYXRtZW50KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbG9yID0gImJsYWNrIikgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC0uMDEsIDEuMDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLS4wMSwgMS4wMSkpICsKICBmYWNldF9ncmlkKElzb2xhdGUxIH4gSXNvbGF0ZTIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGxhYnMoeCA9ICJFeHBlY3RlZCBpc29sYXRlIGZyZXF1ZW5jeSBieSBPRCIsIAogICAgeSA9ICJDQVNFVSBwcmVkaWN0ZWQgaXNvbGF0ZSBmcmVxdWVuY3kiKSArCiAgZ2d0aXRsZSgiQ0FTRVUgcHJlZGljdGlvbiB2cy4gT0QgZnJlcXVlbmNpZXMiKQpgYGAKCgpgYGB7ciB3YXJuaW5nPUZ9CnAgPC0gcGxvdF9ncmlkKENBU0VVX3BpbG90Ml9wMSwgQ0FTRVVfcGlsb3QyX3AyLCBuY29sID0gMSkKZ2dzYXZlKCJmaWd1cmUvMDJCLUNBU0VVX3BpbG90Ml9jb250cm9sLnBuZyIsIHAsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMTApCmBgYAoKCgpgYGB7ciBldmFsID0gRiwgaW5jbHVkZSA9IEZ9CiMjIyBPdXRjb21lIG9mIHBhaXJ3aXNlIGNvbXBldGl0aW9uCiNUaGVyZSBhcmUgMjQgcGFpcnMgb2YgQzExUjEgYmVlbiBzZXF1ZW5jZWQgaW4gQ0FTRVUgcGlsb3QyLgppZiAoRkFMU0UpIHsKQ0FTRVVfcGlsb3QyIDwtIGZyZWFkKGhlcmU6OmhlcmUoImRhdGEvdGVtcC9DQVNFVV9waWxvdDIuY3N2IikpICU+JSAKICBmaWx0ZXIoVHJlYXRtZW50ID09ICJDMTFSMSIpICU+JQogIG11dGF0ZShDb21tdW5pdHkgPSBUcmVhdG1lbnQpICU+JQogIHNlbGVjdChDb21tdW5pdHksIElzb2xhdGUxLCBJc29sYXRlMiwgSXNvbGF0ZTFGcmVxLCBJc29sYXRlMkZyZXEsIElzb2xhdGUxRnJlcVByZWRpY3RlZCwgSXNvbGF0ZTJGcmVxUHJlZGljdGVkKSAlPiUKICBpbnZuZXQ6OnN3aXRjaF9wYWlyd2lzZV9jb2x1bW4oKQoKQ0FTRVVfcGlsb3QyICU+JSAKICBtdXRhdGUoUGFpciA9IHBhc3RlMChJc29sYXRlMSwgIl8iLCBJc29sYXRlMikpICU+JQogIGdncGxvdChhZXMoeCA9IElzb2xhdGUxRnJlcSwgeSA9IElzb2xhdGUxRnJlcVByZWRpY3RlZCwgY29sb3IgPSBQYWlyLCBHcm91cCA9IFBhaXIpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9saW5lKCkgKwojICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbG9yID0gImJsYWNrIikgKwogIGZhY2V0X3dyYXAoLn5Db21tdW5pdHkpICsKICB0aGVtZV9idygpCiAgICAKfQpgYGAKCgojIyBDQVNFVSBwaWxvdDMKClRoZSBwbGF0ZSBsYXlvdXQgb2YgUENSIHBsYXRlIGFuZCBsaXN0IG9mIHNhbXBsZXMgYXJlIHNwZWNpZmllZCBpbiBgb3V0cHV0L3Byb3RvY29sL3Byb3RvY29sXzIwMTkwOTIzX1NlcXVhbFByZXBfU2FuZ2VyX3ByZXAucGRmYC4gCgpgYGB7cn0KZnJlYWQoaGVyZTo6aGVyZSgib3V0cHV0L3Byb3RvY29sL3RhYl9maWcvcHJvdG9jb2xfMjAxOTA5MjRfU2FuZ2VyX3NlcV9wcmVwLWdlbmV3aXpfdGFibGVfQ1lDLmNzdiIpKQpgYGAKClJlYWQgdHJhY2UgbWF0cmljZXMgZm9yIGlzb2xhdGVzIGFuZCBtaXh0dXJlcwoKYGBge3IgZXZhbCA9IEZ9CiMgSXQgdGFrZXMgYWJvdXQgfjE1IG1pbnMgdG8gcnVuIAppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQi1DQVNFVV9zYW5nZXJfc2VxLTA0LXBpbG90My5SIikKYGBgCgpgYGB7cn0KQ0FTRVVfcGlsb3QzIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9DQVNFVV9waWxvdDMuY3N2IikpCkNBU0VVX3BpbG90MyAlPiUKICBtdXRhdGUoSXNvbGF0ZTEgPSBmYWN0b3IoSXNvbGF0ZTEpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBJc29sYXRlMUZyZXEsIHkgPSBJc29sYXRlMUZyZXFQcmVkaWN0ZWQsIGNvbG9yID0gSXNvbGF0ZTEsIGdyb3VwID0gcGFzdGUwKElzb2xhdGUxLCAiXyIsIElzb2xhdGUyKSkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX2xpbmUoKSArCiMgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiYmxhY2siKSArCiAgZmFjZXRfd3JhcCgufkNvbW11bml0eSkgKwogIHRoZW1lX2J3KCkKYGBgCgoKIyMgQ0FTRVUgcGlsb3Q0CgpUaGUgcGxhdGUgbGF5b3V0IG9mIFBDUiBwbGF0ZSBhbmQgbGlzdCBvZiBzYW1wbGVzIGFyZSBzcGVjaWZpZWQgaW4gYG91dHB1dC9wcm90b2NvbC9wcm90b2NvbF8yMDE5MTAwN19TYW5nZXJfc2VxX3ByZXAucGRmYC4gCgpgYGB7cn0KZnJlYWQoaGVyZTo6aGVyZSgib3V0cHV0L3Byb3RvY29sL3RhYl9maWcvcHJvdG9jb2xfMjAxOTEwMDdfU2FuZ2VyX3NlcV9wcmVwLWdlbmV3aXpfdGFibGVfQ1lDLmNzdiIpKQpgYGAKClJlYWQgdHJhY2UgbWF0cmljZXMgZm9yIGlzb2xhdGVzIGFuZCBtaXh0dXJlcwoKYGBge3IgZXZhbCA9IEZ9CiMgSXQgdGFrZXMgYWJvdXQgfjE1IG1pbnMgdG8gcnVuCmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJCLUNBU0VVX3Nhbmdlcl9zZXEtMDUtcGlsb3Q0LlIiKQpgYGAKCgpgYGB7cn0KQ0FTRVVfcGlsb3Q0IDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9DQVNFVV9waWxvdDQuY3N2IikpCkNBU0VVX3BpbG90NCAlPiUKICBtdXRhdGUoSXNvbGF0ZTEgPSBmYWN0b3IoSXNvbGF0ZTEpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBJc29sYXRlMUZyZXEsIHkgPSBJc29sYXRlMUZyZXFQcmVkaWN0ZWQsIGNvbG9yID0gSXNvbGF0ZTEsIGdyb3VwID0gcGFzdGUwKElzb2xhdGUxLCAiXyIsIElzb2xhdGUyKSkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCgufkNvbW11bml0eSkgKwogIHRoZW1lX2J3KCkKYGBgCgoKCiMgMDJDIHBhaXJzX09EX0NGVQoKLSBFcnJvciBwcm9wYWdhdGlvbiB0aGVvcnkKCi0gRGVyaXZlIGlzb2xhdGVzJyAkXGVwc2lsb24kIGZyb20gVDggZGF0YSBhbmQgY2FsY3VsYXRlIHVuY2VydGF0aW50eSB1c2luZyBlcnJvciBwcm9wYWdhdGlvbiB0aGVvcnkKCi0gQ29udmVydCBUMCBPRCBmcmVxdWVuY3kgJGZeTyQgdG8gQ0ZVIGZyZXF1ZW5jeSAkZl5DJCBhbmQgZXN0aW1hdGUgdGhlIHVuY2VydGFpbnR5IGluIGNvbnZlcnRlZCBDRlUgZnJlcXVlbmNpZXMgYXQgVDguIE91dHB1dCBgZGF0YS90ZW1wL3BhaXJzX0NGVV9mcmVxX3VuY2VydGFpbnR5LmNzdmAKCiMjIEdlbmVyYWwgZm9ybXVsYSBvZiBlcnJvciBwcm9wYWdhdGlvbgoKVGhpcyBzZWN0aW9uIGV4cGxhaW5zIHRoZSBlcnJvciBwcm9wYWdhdGlvbiB0aGVvcnkgdG8gZXN0aW1hdGUgdGhlIHVuY2VydGFpbnR5IGluIHRoZSBleHBlcmltZW50YWwgbWVhc3VyZW1lbnQuIFRoZXJlIGFyZSBvbmUgb3IgbW9yZSBxdWFudGl0aWVzICR4LCB5LCAuLi4kLCB3aXRoIGNvcnJlc3BvbmRpbmcgdW5jZXJ0YWludGllcyAkXGRlbHRhIHgsIFxkZWx0YSB5LCAuLi4kIGFuZCB0aGF0IHdlIHdpc2ggdG8gdXNlIHRoZSBtZWFzdXJlZCB2YWx1ZXMgb2YgeCBhbmQgeSB0byBjYWxjdWxhdGUgdGhlIHF1YW50aXR5IG9mIHJlYWwgaW50ZXJlc3QgcS4gVGhlcmUgYXJlIHRocmVlIHByb3Zpc2lvbmFsIHJ1bGVzOgoKMS4gVGhlIHNxdWFyZS1yb290IHJ1bGUgZm9yIGNvdW50aW5nIGV4cGVyaW1lbnRzLiBUaGUgYXZlcmFnZSBudW1iZXIgb2YgZXZlbnQgaW4gdGltZSBUIGlzICR2XHBtXHNxcnR7dn0kCgoyLiBVbmNlcnRhaW50eSBpbiAqKnN1bXMgYW5kIGRpZmZlcmVuY2VzKiouIFRoZSBjb21wdXRlZCBtZWFuIHZhbHVlICRxPXgreSt6LSh1K3cpJC4gSWYgdGhlIHVuY2VydGFpbnRpZXMgaW4geCwgLi4uLCB3IGFyZSBrbm93biB0byBiZSBpbmRlcGVuZGVudCBhbmQgcmFuZG9tLCB0aGVuIHRoZSB1bmNlcnRhaW50eSBpbiB0aGUgY29tcHV0ZWQgdmFsdWUgb2YgcSBpcyB0aGUgcXVhZHJhdGljIHN1bSAkXGRlbHRhIHEgPSBcc3FydHsoXGRlbHRhIHgpXjIrKFxkZWx0YSB5KV4yKyhcZGVsdGEgeileMisoXGRlbHRhIHUpXjIrKFxkZWx0YSB3KV4yfSQgLCBJbiBhbnkgY2FzZSwgJFxkZWx0YSBxJCBpcyBuZXZlciBsYXJnZXIgdGhhbiB0aGVpciBvcmRpbmFyeSBzdW0gJFxkZWx0YSBxIFxsZXFzbGFudCBcZGVsdGEgeCArIFxkZWx0YSB5KyBcZGVsdGEgeiArIFxkZWx0YSB1ICsgXGRlbHRhIHckCgozLiBVbmNlcnRhaW50eSBpbiAqKnByb2R1Y3QgYW5kIHF1b3RpZW50cyoqLiAkcT1cZnJhY3t4XHRpbWVzIHp9e3VcdGltZXMgd30kLCB0aGVuIHRoZSBmcmFjdGlvbmFsIHVuY2VydGFpbnR5IGluIHRoZSBjb21wdXRlZCB2YWx1ZSBxIGlzIHRoZSBzdW0uIElmIHRoZSB1bmNlcnRhaW50aWVzIGluIHgsIC4uLix3IGFyZSBpbmRlcGVuZGVudCBhbmQgcmFuZG9tLCB0aGVuIHRoZSBmcmFjdGlvbmFsIHVuY2VydGFpbnR5IGluIHEgaXMgdGhlIHN1bSBpbiBxdWFkcmF0dXJlIG9mIHRoZSBvcmlnaW5hbCB1bmNlcnRhaW50aWVzLCAkXGZyYWN7XGRlbHRhIHF9e1xsZWZ0fHFccmlnaHR8fSA9IFxzcXJ0eyhcZnJhY3tcZGVsdGEgeH17XGxlZnR8eFxyaWdodHx9KV4yICsgXGZyYWN7XGRlbHRhIHl9e1xsZWZ0fHlccmlnaHR8fSleMiArXGZyYWN7XGRlbHRhIHp9e1xsZWZ0fHpccmlnaHR8fSleMiArXGZyYWN7XGRlbHRhIHV9e1xsZWZ0fHVccmlnaHR8fSleMiArIFxmcmFje1xkZWx0YSB3fXtcbGVmdHx3XHJpZ2h0fH0pXjJ9JC4gJFxmcmFje1xkZWx0YSBxfXtcbGVmdHwgcSBccmlnaHR8fSBcbGVxc2xhbnQgXGZyYWN7XGRlbHRhIHh9e1xsZWZ0fCB4IFxyaWdodHx9ICsgXGZyYWN7XGRlbHRhIHp9e1xsZWZ0fCB6IFxyaWdodHx9ICsgXGZyYWN7XGRlbHRhIHV9e1xsZWZ0fCB1IFxyaWdodHx9ICsgXGZyYWN7XGRlbHRhIHd9e1xsZWZ0fCB3IFxyaWdodHx9JCAKClRha2luZyB0aGVzZSB0aHJlZSBwcm92aXNpb25hbCBydWxlcyB0b2dldGhlciwgdGhlIGdlbmVyYWwgZm9ybXVsYSBmb3IgZXJyb3IgcHJvcGFnYXRpb24gdGFrZXMgdGhlIGZvbGxvd2luZyBmb3JtLiBBc3N1bWUgdGhlIGNvbXB1dGVkIHF1YW50aXR5IGlzIGEgZnVuY3Rpb24gb2YgJHhfMSwgeF8yLCAuLi4sIHhfbiQsIHRoZSB1bmNlcnRhaW50eSBpbiBxIGlzICQkXGRlbHRhIHE9IFxzcXJ0eyhcc3Vte1xmcmFje1xwYXJ0aWFsIHF9e1xwYXJ0aWFsIHhfaX19XGRlbHRhIHhfaSleMn0kJCAKCgoKIyMgVW5jZXJ0YWludHkgaW4gZXBzaWxvbiAKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQy1wYWlyc19PRF9DRlUtMDEtZXBzaWxvbl91bmNlcnRhaW50eS5SIikKYGBgCgoKVGhlIHVuY2VydGFpbnRpZXMgaW4gZWFjaCBpc29sYXRlJyBlcHNpbG9uICRcZXBzaWxvbl9BID0gXGZyYWN7T0RfQSBERl9BIHZfQX17Q0ZVX0F9JCBjb21lcyBmcm9tIGZvdXIgcGFydHM6CgoxLiAkREYkOiBEaWx1dGlvbiBmYWN0b3JzLiBUaGUgdW5jZXJ0YWludHkgY29tZXMgZnJvbSB0aGUgcGlwZXR0aW5nIGluIHNlcmlhbCBkaWx1dGlvbiwgd2hpY2ggaXMgY2FsY2F1bHRlZCBiZWxvdy4KMi4gJHYkOiBQbGF0aW5nIHZvbHVtZXMuIFRoZSBzeXN0ZW1hdGljIGVycm9yIGZvciBQMjAgc2V0IGF0IDIwIHVMIGlzIDAuNCB1TC4KMy4gJENGVSQ6IENGVSBjb3VudHMuIFRoZSB1bmNlcnRhaW50eSBpbiBDRlUgZm9sbG93cyBwb2lzc29uIGRpc3RyaWJ1dGlvbiwgd2hpY2ggbWVhbnMgdGhhdCB0aGUgdmFyaWFuY2UgaXMgdGhlIHNhbWUgYXMgdGhlIG1lYW4gKG1lYXN1cmVkIENGVSkuIFRoZSBzdGFuZGFyZCBkZXZpYXRpb24gaXMgJFxzcXJ0e0NGVX0kLgo0LiAkT0QkOiBPRCBtZWFzdXJlbWVudC4gVGhlIHVuY2VydGFpbnR5IGluIG1lYXN1cmluZyBPRCBpbiBwbGF0ZSByZWFkZXIsIHdoaWNoIGlzIGFzc3VtZWQgdG8gYmUgMC4wMDEuCgoKKipEaWx1dGlvbiBmYWN0b3IqKgoKVGhlIHVuY2VydGFpbnR5IGluIGRpbHV0aW9uIGZhY3RvciBjb21lcyBmcm9tIHRoZSBwaXBldHRpbmcgc3RlcHMgaW4gc2VyaWFsIGRpbHV0aW9uLCB3aGljaCBpbmNsdWRlIHR3byBwaXBldHRpbmcgdm9sdW1lczoKCjEuIGBWMWA6IHNlcmlhbCBkaXNwZW5zaW5nIDEwIHVMIG9mIGRpbHV0ZWQgc29sdXRpb24gdXNpbmcgbVAyMC4gSXQgaGFzIHVuY2VydGFpbnR5IGBFcnJvclYxYCAyIHVMLgoyLiBgVjJgOiBkaXNwZW5zZSA5MCB1TCBvZiBQQlMgdXNpbmcgbVAyMDAuIEl0IGhhcyB1bmNlcnRhaW50eSBgRXJyb3JWMmAgMC40IHVMLgoKRm9yIGRpbHV0aW9uIGZhY3RvciAkMTBee259JCwgaXQgaGFzIHRoZSB0aGUgbWVhbiAkKFxmcmFje1ZfMX17Vl8xK1ZfMn0pXm4kLiBUbyBvYnRhaW4gdGhlIHVuY2VydGFpbnR5IGluIHRoZSBtZWFzdXJlZCBtZWFuLCBmaXJzdCB3ZSBjYWx1Y3VsYXRlIHRoZSBwYXJ0aWFsIGRlcml2YXRpdmVzICRcZnJhY3tccGFydGlhbCBERn17XHBhcnRpYWwgVl8xfSQgYW5kICRcZnJhY3tccGFydGlhbCBERn17XHBhcnRpYWwgVl8yfSQuIFRoZW4gdGhlIHVuY2VydGFpbnR5ICRcZGVsdGEgREYgPSBcc3FydHsoXGZyYWN7XHBhcnRpYWwgREZ9e1xwYXJ0aWFsIFZfMX1cZGVsdGEgVl8xKV4yICsgKFxmcmFje1xwYXJ0aWFsIERGfXtccGFydGlhbCBWXzJ9XGRlbHRhIFZfMileMn0kCgoKYGBge3J9CmRpbHV0aW9uX2ZhY3RvciA8LSAKICBkYXRhLmZyYW1lKG4gPSBjKDQsIDUpLCBWMSA9IDEwLCBWMiA9IDkwLCBFcnJvclYxID0gMC40LCBFcnJvclYyID0gMikgJT4lCiAgbXV0YXRlKFBhcnRpYWxWMSA9IG4gKiBWMV4obi0xKSAqIFYyIC8gKFYxK1YyKV4obisxKSwgIy1uKihWMStWMileKG4tMSkqVjIvKFYxXihuKzEpKSwKICAgICAgICAgUGFydGlhbFYyID0gLW4gKiBWMV4obi0xKSAvIChWMStWMileKG4rMSksICNuKihWMStWMileKG4tMSkvKFYxXm4pLAogICAgICAgICBERiA9IChWMS8oVjErVjIpKV5uLAogICAgICAgICBFcnJvckRGID0gc3FydCgoUGFydGlhbFYxKkVycm9yVjEpXjIgKyAoUGFydGlhbFYyKkVycm9yVjIpXjIpKQoKZGlsdXRpb25fZmFjdG9yCmBgYAoKCkJ5IHVzaW5nIGVycm9yIHByb3BhZ2F0aW9uIHRoZXJveSwgdGhlIHVuY2VydGFpbnR5IGluIGlzb2xhdGVzIGVwc2lsb24gaGFzIHRoZSBmb3JtIAoKJCRcZGVsdGEgXGVwc2lsb24gPSBcc3FydHsoXGZyYWN7XHBhcnRpYWwgIFxlcHNpbG9ufXtccGFydGlhbCBERn1cZGVsdGEgREYpXjIgKyhcZnJhY3tccGFydGlhbCAgXGVwc2lsb259e1xwYXJ0aWFsIENGVX1cZGVsdGEgQ0ZVKV4yICsgKFxmcmFje1xwYXJ0aWFsICBcZXBzaWxvbn17XHBhcnRpYWwgT0R9XGRlbHRhIE9EKV4yICsgKFxmcmFje1xwYXJ0aWFsICBcZXBzaWxvbn17XHBhcnRpYWwgVn1cZGVsdGEgVileMn0kJAoKCmBgYHtyfQppc29sYXRlc19lcHNpbG9uX3VuY2VydGFpbnR5IDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9pc29sYXRlc19lcHNpbG9uX3VuY2VydGFpbnR5LmNzdiIpKQppc29sYXRlc19lcHNpbG9uX3VuY2VydGFpbnR5CmBgYAoKVGhlcmUgYXJlIDcgaXNvbGF0ZXMgdGhhdCBoYXZlIGVpdGhlciAwIENGVSBvciBuZWdhdGl2ZSBPRCB2YWx1ZSwgc28gdGhleSBkb24ndCBoYXZlIGVwc2lsb24gdmFsdWVzLgoKYGBge3J9Cmlzb2xhdGVzX2Vwc2lsb25fdW5jZXJ0YWludHkgJT4lCiAgZmlsdGVyKGlzLm5hKEVwc2lsb24pKQpgYGAKCiMjIENvbnZlcnQgVDAgT0QgZnJlcXVlbmNpZXMgdG8gQ0ZVIGZyZXF1ZW5jaWVzCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkMtcGFpcnNfT0RfQ0ZVLTAyLUNGVV9mcmVxdWVuY3kuUiIpCmBgYAoKVGhlIG91dGNvbWUgb2YgcGFpcndpc2UgY29tcGV0aXRpb24gd2VyZSBkZXRlcm1pbmVkIGJ5IGNvbXBhcmluZyB0aGUgZnJlcXVlbmN5IGNoYW5nZXMgYmV0d2VlbiBUMCBhbmQgVDguIFRoZSBUOCBmcmVxdWVuY2llcyB3ZXJlIGRldGVybWluZWQgYnkgcGxhdGluZyB0aGUgbWF0dXJlIG1lZGlhIG9uIHJpY2ggYWdhciBtZWRpYSBvbiB3aGljaCB0aGUgY29sb25pZXMgd2VyZSBjb3VudGVkLCB3aGVyZWFzIFQwIGZyZXF1ZW5jaWVzIHdlcmUgc2V0IHRvIDk1LzUsIDUwLzUwIGFuZCA1Lzk1IGJ5IG1peGluZyB0d28gaXNvbGF0ZSBpbm9jdWxhIHdpdGggZXF1YWwgT0QuICBJbiB0aGlzIHNlY3Rpb24sIEkgd2lsbCB1c2UgdGhlIE9ELUNGVSBjb252ZXJzaW9uIGNvZWZmaWNpZW50ICRcZXBzaWxvbiQgZGVyaXZlZCBmcm9tIFQ4IGlzb2xhdGUgZGF0YSB0byBjb252ZXJ0IFQwIE9EIGZyZXF1ZW5jaWVzIGludG8gQ0ZVIGZyZXF1ZW5jaWVzLiBJbiBzcGVjaWZpYywgdGhlIENGVSBmcmVxdWVuY3kgb2YgaXNvbGF0ZSAxICRmXkNfMSQgb2YgYSBwYWlyIGNhbiBiZSBkZXJpdmVkIGZyb20gT0QgZnJlcXVlbmNpZXMgb2YgaXNvbGF0ZSAxIGFuZCAyICRmXk9fMSAsZl5PXzIkLCB3aGljaCBoYXZlIHRoZSByZWxhdGlvbnNoaXAgYmVsb3cuIAoKJGZeQ18xID0gXGZyYWN7Zl5vXzFcZXBzaWxvbl8xREZ2fXtmXm9fMVxlcHNpbG9uXzFERnYgKyBmXm9fMlxlcHNpbG9uXzJERnZ9PVxmcmFje2Zeb18xXGVwc2lsb25fMX17Zl5vXzFcZXBzaWxvbl8xICsgZl5vXzJcZXBzaWxvbl8yfSQKCndoZXJlICRcZXBzaWxvbiQgb2YgZWFjaCBpc29sYXRlIHdhcyBwcmUtY2FsY3VsYXRlZCBmcm9tIFQ4IGRhdGFzZXQuIERGIGFuZCB2IGFyZSB0aGUgc2FtZSBpbiBjb252ZXJzaW9uLgoKYGBge3J9CnBhaXJzX0NGVV9mcmVxIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wYWlyc19DRlVfZnJlcS5jc3YiKSkKcGFpcnNfQ0ZVX2ZyZXEKYGBgCgoKIyMgVW5jZXJ0YWludHkgaW4gVDAgQ0ZVIGZyZXF1ZW5jaWVzCgpgYGB7ciB3YXJuaW5nID0gRn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkMtcGFpcnNfT0RfQ0ZVLTAzLUNGVV9mcmVxdWVuY3lfdW5jZXJ0YWludHkuUiIpCmBgYAoKV3JpdGUgQ0ZVIGZyZXF1ZW5jaWVzIHRvIGBkYXRhL3RlbXAvcGFpcnNfQ0ZVX2ZyZXFfdW5jZXJ0YWludHkuY3N2YAoKYGBge3J9CnBhaXJzX0NGVV9mcmVxX3VuY2VydGFpbnR5IDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wYWlyc19DRlVfZnJlcV91bmNlcnRhaW50eS5jc3YiKSkKcGFpcnNfQ0ZVX2ZyZXFfdW5jZXJ0YWludHkKYGBgCgoKIyAwMkQgZGV0ZXJtaW5lIHBhaXJ3aXNlIGludGVyYWN0aW9uCgojIyBDb21iaW5lIG91dGNvbWVzIG9mIHBhaXJ3aXNlIGNvbXBldGl0aW9uIGZyb20gQ0ZVIGNvdW50cyBhbmQgQ0FTRVUKClJhdyBkYXRhIChlLmcuLCBDRlUgY291bnRzIGFuZCBDQVNFVSBTYW5nZXIgc2VxdWVuY2VzKSBhcmUgcHJvY2Vzc2VkIGFuZCBnZW5lcmF0ZWQgaW50byB0ZW1wb3JhcnkgcmVzdWx0IGNzdjoKCjEuIGAwMkItQ0FTRVVfc2FuZ2VyX3NlcWAgcmVhZHMgQ0FTRVUgcmF3IGRhdGEgYW5kIG91dHB1dHMgYHRlbXAvQ0FTRVVfcGlsb3QyLmNzdmAgYW5kIGB0ZW1wL0NBU0VVX3BpbG90My5jc3ZgLiBCb3RoIGZpbGVzIGFyZSBDQVNFVSBwcmVkaWN0ZWQgVDggZnJlcXVlbmNpZXMuCgoyLiBgMDJDLXBhaXJzX09EX0NGVWAgcmVhZHMgcGFpcl9jb21wZXRpdGlvbiBhbmQgZGlsdXRpb24gZmFjdG9yIGRhdGEsIGFuZCBpdCBvdXRwdXRzIGB0ZW1wL3BhaXJzX0NGVV9mcmVxX3VuY2VydGFpbnR5LmNzdmAsIHdoaWNoIGhhcyB0aGUgVDAgT0QtY29udmVydGVkIENGVSBmcmVxdWVuY2llcyBhbmQgVDggQ0ZVIGZyZXF1ZW5jaWVzIHdpdGggdW5jZXJ0YWludGllcy4KCioqTm90ZSB0aGF0IGlmIGEgcGFpciBoYXMgYm90aCBDRlUgYW5kIENBU0VVIHJlc3VsdCwgQ0FTRVUgd2lsbCBvdmVyd3JpdGUgdGhlIENGVSByZXN1bHQqKgoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJELWRldGVybWluZV9wYWlyd2lzZV9pbnRlcmFjdGlvbi0wMS1jb21iaW5lX0NGVV9DQVNFVV9yZXN1bHQuUiIpCmBgYAoKVGhlIHNjcmlwdCBpbiB0aGlzIHNlY3Rpb24gcmV0dXJucyBhIGRhdGEuZnJhbWUgYHBhaXJzX2ZyZXFgIHRoYXQgaGFzIHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzOgoKLSBgQ29tbXVuaXR5YAotIGBJc29sYXRlMWAgYW5kIGBJc29sYXRlMmA6IGluZGljZXMgb2YgaXNvbGF0ZXMgd2l0aGluIGEgY29tbXVuaXR5LiBUaGUgbnVtYmVyIG9mIGlzb2xhdGUxIGlzIGFsd2F5cyBzbWFsbGVyIHRoYW4gaXNvbGF0ZTIKLSBgSXNvbGF0ZTFJbml0aWFsT0RGcmVxYCBhbmQgYElzb2xhdGUySW5pdGlhbE9ERnJlcWA6IDUsIDUwIG9yIDk1LiBUaGUgaW5pdGlhbCBPRCBmcmVxdWVuY2llcyBvZiBpc29sYXRlcyBhdCBUMC4gVGhpcyB0d28gc2VydmUgYXMgZGlzY3JldGUgZ3JvdXBpbmcgdmFyaWFibGVzLgotIGBUaW1lYDogVDAgb3IgVDguCi0gYElzb2xhdGUxTWVhc3VyZWRGcmVxYDogdGhlIG1lYXN1cmVkIGZyZXF1ZW5jeSBvZCBpc29sYXRlMSBpbiB0aGUgcGFpci4gCi0gYEVycm9ySXNvbGF0ZTFNZWFzdXJlZEZyZXFgOiB0aGUgdW5jZXJ0YWludHkgb2YgYElzb2xhdGUxTWVhc3VyZWRGcmVxYC4KLSBgUmF3RGF0YVR5cGVgOiBPRCwgT0R0b0NGVSwgQ0ZVLCBTYW5nZXIgKENBU0VVKS4gVGhlIHJhdyBkYXRhIHR5cGUgaW4gd2hpY2ggdGhlIGlzb2xhdGUgZnJlcXVlbmNpZXMgd2VyZSBtZWFzdXJlZC4KLSBgQ29udGFtaW5hdGlvbmA6IGxvZ2ljYWwuIFRoZXJlIGFyZSBjb250YW1pbmF0aW9ucyBpbiB0aHJlZSBwYWlycyBhdCBUOCBwbGF0ZXMuCgoxODZ4M3gyPTExMTYgcGFpci1mcmVxIGF0IHR3byB0aW1lIHBvaW50cwoKYGBge3J9CnBhaXJzX2ZyZXEgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvcGFpcnNfZnJlcS5jc3YiKSkKcGFpcnNfZnJlcQpgYGAKCgpUaGVyZSBpcyBvbmUgcGFpci1mcmVxIHRoYXQgY2Fubm90IGJlIHNwZWNpZmllZCBiZWNhdXNlIG9mIGNvbnRhbWluYXRpb24uCgpgYGB7cn0KcGFpcnNfZnJlcSAlPiUKICBmaWx0ZXIoVGltZSA9PSAiVDgiKSAlPiUKICBmaWx0ZXIoaXMubmEoSXNvbGF0ZTFNZWFzdXJlZEZyZXEpKQpgYGAKCgojIyBEZXRlcm1pbmUgcGFpcndpc2UgaW50ZXJhY3Rpb25zCgpgYGB7ciB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJELWRldGVybWluZV9wYWlyd2lzZV9pbnRlcmFjdGlvbi0wMi1kZXRlcm1pbmVfcGFpcndpc2VfaW50ZXJhY3Rpb24uUiIpCmBgYAoKClBsb3QgZnJlcXVlbmN5IGNoYW5nZXMuIE91dHB1dCBmaWd1cmUgb2YgQ0ZVIGZyZXF1ZW5jeSBjaGFuZ2VzIHRvIGBvdXRwdXQvZmlndXJlL3BhaXJzX2ZyZXFfY2hhbmdlX3VuY2VydGFpbnR5LnBkZmAKCmBgYHtyIGV2YWwgPSBGfQpsb2FkKGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wX3BhaXJzX2ZyZXFfY2hhbmdlX2xpc3QuUmRhdGEiKSkKcGRmKGhlcmU6OmhlcmUoIm91dHB1dC9yZXBvcnQvZmlndXJlLzAyRC1mcmVxX2NoYW5nZV91bmNlcnRhaW50eS5wZGYiKSwgaGVpZ2h0ID0gMTAgLCB3aWR0aCA9IDEwKTsgZm9yIChpIGluIDE6bGVuZ3RoKGNvbW11bml0aWVzJENvbW11bml0eSkpIHByaW50KHBfcGFpcnNfZnJlcV9jaGFuZ2VfbGlzdFtbaV1dKTsgaW52aXNpYmxlKGRldi5vZmYoKSkKYGBgCgpUYWJsZSBvZiBhbGwgMjcgcG9zc2libGUgY29tYmluYXRpb25zIG9mIGZpdG5lc3MgZnVuY3Rpb24gYW5kIHRoZWlyIGludGVyYWN0aW9uIHR5cGVzIAoKYGBge3J9CmludGVyYWN0aW9uX3R5cGUgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL2ludGVyYWN0aW9uX3R5cGUuY3N2IikpCmludGVyYWN0aW9uX3R5cGUKYGBgCgoKVGFibGUgb2YgaW50ZXJhY3Rpb24gdHlwZXMKCmBgYHtyfQpwYWlyc19pbnRlcmFjdGlvbl9maXRuZXNzIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wYWlyc19pbnRlcmFjdGlvbl9maXRuZXNzLmNzdiIpKQpwYWlyc19pbnRlcmFjdGlvbl9maXRuZXNzICU+JQogIGdyb3VwX2J5KEludGVyYWN0aW9uVHlwZSkgJT4lCiAgc3VtbWFyaXplKENvdW50ID0gbigpKSAKYGBgCgpJbnRlcmFjdGlvbiB0YWJsZQoKYGBge3J9CnBhaXJzX2ludGVyYWN0aW9uX3RhYmxlIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wYWlyc19pbnRlcmFjdGlvbl90YWJsZS5jc3YiKSkKcGFpcnNfaW50ZXJhY3Rpb25fdGFibGUKYGBgCgoKIyMgSXNvbGF0ZSB0b3VybmFtZW50CgoKYGBge3Igd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyRC1kZXRlcm1pbmVfcGFpcndpc2VfaW50ZXJhY3Rpb24tMDMtaXNvbGF0ZV90b3VybmFtZW50LlIiKQpgYGAKClRvdXJuYW1lbnQgcmFua3Mgb2YgZWFjaCBpc29sYXRlLiBOb3RlIHRoYXQgSSBjb25zaWRlciBuZXR1cmFsaXR5IGFuZCBiaXN0YWJpbGl0eSBhcyBkcmF3IGluIHRoZSB0b3VybmFtZW50LgoKLSBgU2NvcmVgOiB0aGUgY29tcGV0aXRpdmUgc2NvcmVzIG9mIGlzb2xhdGUuIFRoaXMgc2NvcmUgaXMgY29tcHV0ZWQgYnkgdGhlIGZvcm11bGE6IG51bWJlciBvZiB3aW5zIC0gbnVtYmVyIG9mIGxvc2VzICsgMCAqIG51bWJlciBvZiBkcmF3cy4gCi0gYEdhbWVgOiBudW1iZXIgb2YgcGFpcndpc2UgY29tcGV0aXRpb24gdGhlIGlzb2xhdGUgaGFzIHBsYXllZC4gVGhlIG51bWJlciBvZiBnYW1lcyBhbiBpc29sYXRlIHBsYXRlZCB3aXRoaW4gYSBjb21tdW5pdHkgc2hvdWxkIGJlIGNvbW11bml0eSBzaXplIG1pbnVzIG9uZS4gCi0gYFJhbmtgOiB0aGUgcmFua3MgYmFzZWQgb24gYFNjb3JlYC4gVGhlIHJhbmtzIHJhbmdlIGZyb20gMSB0byB0aGUgZm9jYWwgY29tbXVuaXR5IHNpemUuIElzb2xhdGVzIHdpdGggdGhlIHNhbWUgc2NvcmVzIGluIGEgY29tbXVuaXR5IGFyZSBnaXZlbiB0aGUgc2FtZSByYW5rLgotIGBQbG90UmFua2A6IGNvbnRpbnVvdXMgcmFuayBmb3IgcGxvdHRpbmcgY29udmVuaWVuY2UuCgoKIyAwMkUgY29tcGV0aXRpb24gcGh5bG9nZW55CgotIENvcnJlbGF0ZSBjb21wZXRpdGlvbiByZXN1bHQgd2l0aCBwaHlsb2dlbmV0aWMgZGlzdGFuY2UKCi0gTWVhc3VyZSB0aGUgcGFpcndpc2UgcGh5bG9nZW5ldGljIGRpc3RhbmNlcyBieSBkaWZmZXJlbmNlIGluIDE2UyBiYXNlIHBhaXJzIGBwYWlyc190YXhvbm9teWAKICAgIC0gQ29hcnNlLWdyYWluZWQgdGF4b25vbXkgKEZhbWlseSBhbmQgR2VudXMpCiAgICAtIENvbXB1dGUgdGhlIHBhaXJ3aXNlIHNlcXVlbmNlIGRpZmZlcmVuY2VzIHVzaW5nIGBCaW9zdHJpbmc6OnBhaXJ3aXNlQWxpZ25tZW50KClgIAogICAgLSBDb21wdXRlIHBhaXJ3aXNlIHRyZWUgZGlzdGFuY2UgdXNpbmcgYGFwZTo6Y29waGVuZXRpYy5waHlsbygpYCBvbiBidWlsdCB0cmVlLiBUcnkgb3V0IGRpZmZlcmVudCB0cmVlIGJ1aWxkaW5nIG1ldGhvZHMKCgojIyBJc29sYXRlcycgUkRQIHRheG9ub215CgpgYGB7ciB3YXJuaW5nID0gRn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkUtY29tcGV0aXRpb25fcGh5bG9nZW55LTAxLXBhaXJzX3RheG9ub215LlIiKQpgYGAKCmBgYHtyfQpwYWlyc190YXhvbm9teSA8LSByZWFkX2NzdihoZXJlOjpoZXJlKCJkYXRhL3RlbXAvcGFpcnNfdGF4b25vbXkuY3N2IikpCnBhaXJzX3RheG9ub215CmBgYAoKCgojIyBJc29sYXRlcycgMTZTIHNlcXVlbmNlIGRpZmZlcmVuY2UKCgpgYGB7ciBldmFsID0gRn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkUtY29tcGV0aXRpb25fcGh5bG9nZW55LTAyLXBhaXJzXzE2Uy5SIikKYGBgCgpgYGB7cn0KcGFpcnNfMTZTIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wYWlyc18xNlMuY3N2IikpCnBhaXJzXzE2UwpgYGAKCgpgYGB7ciBpbmNsdWRlID0gRn0KIyBQbG90IHRoZSBpc29sYXRlIDE2UyBhbGlnbm1lbnRzCmlmIChGQUxTRSkgewptc2E6Om1zYVByZXR0eVByaW50KGFsbiwgZmlsZSA9ICJpc29sYXRlc19hbGlnbm1lbnQucGRmIiwgb3V0cHV0PSJwZGYiLCAKICBwYXBlckhlaWdodCA9IDE1LCBwYXBlcldpZHRoID0gMTAsCiAgc2hvd05hbWVzPSJsZWZ0IiwgYXNrRm9yT3ZlcndyaXRlPUZBTFNFLCB2ZXJib3NlPUZBTFNFKQp9CmBgYAoKCiMjIElzb2xhdGVzJyBicmFuY2ggZGlzdGFuY2VzIG9uIHBoeWxvZ2VuZXRpYyB0cmVlIChkZXByZWNhdGVkKQoKYGBge3Igd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyRS1jb21wZXRpdGlvbl9waHlsb2dlbnktMDMtcGFpcnNfdHJlZV9icmFuY2guUiIpCmBgYAoKYGBge3J9CnBhaXJzX3RyZWVfZGlzdGFuY2UgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL3BhaXJzX3RyZWVfZGlzdGFuY2UuY3N2IikpCnBhaXJzX3RyZWVfZGlzdGFuY2UKYGBgCgoKIyBTdW1tYXJ5CgojIyBSZWFkIGFuZCBjb21iaW5lIHBhaXJzIGRhdGEgCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMi1wYWlycy0wMS1yZWFkX2RhdGEuUiIpCmBgYAoKMTg2IHBhaXJzCgpgYGB7cn0KcGFpcnMgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvcGFpcnMuY3N2IikpCnBhaXJzCmBgYAoKClBhaXJzIGRhdGEuZnJhbWUgbWVsdGVkIGJ5IFQwL1Q4IGFuZCB0aHJlZSBpbml0aWFsIGZyZXF1ZW5jaWVzLiAxODZ4M3gyPTExMTYKCmBgYHtyfQpwYWlyc19tZWx0ZWQgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvcGFpcnNfbWVsdGVkLmNzdiIpKQpwYWlyc19tZWx0ZWQKYGBgCgojIyBQbG90IG91dGNvbWVzIHR5cGVzCgpgYGB7ciB3YXJuaW5nID0gRn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMi1wYWlycy0wMi1vdXRjb21lX3R5cGVzLlIiKQpgYGAKCmBgYHtyfQojIHBhaXJzX2xpc3QgPC0gcGFpcnNfZXhhbXBsZV9vdXRjb21lcwojIHBhaXJzX2ZyZXFfZGYgPC0gcGFpcnNfZnJlcQojIFIgZnVuY3Rpb24gZm9yIHBsb3R0aW5nIGZyZXF1ZW5jeSBjaGFuZ2VzCnBsb3RfcGFpcnNfZnJlcSA8LSBmdW5jdGlvbihwYWlyc19saXN0LCBwYWlyc19mcmVxX2RmLCBzaG93X3N0cmlwID0gVFJVRSkgewogICMgQSBsaXN0IG9mIHBhaXJzIHdpdGggQ29tbXVuaXR5LCBJc29sYXRlMSwgYW5kIElzb2xhdGUyCiAgcGFpcnNfbGlzdCAlPiUKICAgICMgSm9pbnQgdGhlIGRmIGBwYWlyc19mcmVxYCB0aGF0IHNhdmVzIGZyZXF1ZW5jeSBkYXRhCiAgICBsZWZ0X2pvaW4ocGFpcnNfZnJlcV9kZiwgYnkgPSBjKCJDb21tdW5pdHkiLCAiSXNvbGF0ZTEiLCAiSXNvbGF0ZTIiKSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUoSXNvbGF0ZTFJbml0aWFsT0RGcmVxID0gZmFjdG9yKElzb2xhdGUxSW5pdGlhbE9ERnJlcSksCiAgICAgIEludGVyYWN0aW9uVHlwZSA9IG9yZGVyZWQoSW50ZXJhY3Rpb25UeXBlLCBjKCJleGNsdXNpb24iLCAiYmlzdGFiaWxpdHkiLCAiY29leGlzdGVuY2UiLCAibmV1dHJhbGl0eSIpKSwKICAgICAgSW50ZXJhY3Rpb25UeXBlRmluZXIgPSBvcmRlcmVkKEludGVyYWN0aW9uVHlwZUZpbmVyLCBjKCJjb21wZXRpdGl2ZSBleGNsdXNpb24iLCAibXV0dWFsIGV4Y2x1c2lvbiIsCiAgICAgICAgInN0YWJsZSBjb2V4aXN0ZW5jZSIsICJmcmVxdWVuY3ktZGVwZW5kZW50IGNvZXhpc3RlbmNlIiwgIm5ldXRyYWxpdHkiKSkpICU+JQogICAgZ2dwbG90KGFlcyh4ID0gVGltZSwgeSA9IElzb2xhdGUxTWVhc3VyZWRGcmVxLCBjb2xvciA9IElzb2xhdGUxSW5pdGlhbE9ERnJlcSwgZ3JvdXAgPSBJc29sYXRlMUluaXRpYWxPREZyZXEpKSArCiAgICBnZW9tX3BvaW50KHNpemUgPSAyKSArCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxLDAuNSkpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoCiAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoNSwgIm1tIiksCiAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkKICAgICAgKSArCiAgICAgIHtpZiAoc2hvd19zdHJpcCA9PSBGQUxTRSkgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgc3RyaXAudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSl9ICsKICAgIGd1aWRlcyhjb2xvciA9IEYpICsKICAgIGxhYnMoeCA9ICJ0cmFuc2ZlciIsIHkgPSAiaXNvbGF0ZSByZWxhdGl2ZSBhYnVuZGFuY2UiKQp9CmBgYAoKCmBgYHtyfQojIFIgZnVuY3Rpb24gZm9yIHBsb3R0aW5nIGJhcnMKcGxvdF9iYXIgPC0gZnVuY3Rpb24ocGFpcnMsIGJhcl9ieSA9ICJJbnRlcmFjdGlvblR5cGUiLCBmaWxsX2J5ID0gIkludGVyYWN0aW9uVHlwZSIsIHNob3dfZmlsbF9sZWdlbmQgPSBGKSB7CiAgIyBNb2RpZnkgYmFycwogIHBhaXJzJEludGVyYWN0aW9uVHlwZUZpbmVyW3BhaXJzJEludGVyYWN0aW9uVHlwZUZpbmVyID09ICJmcmVxdWVuY3ktZGVwZW5kZW50IGNvZXhpc3RlbmNlIl0gPC0gImZyZXF1ZW5jeS1kZXBlbmRlbnRcbmNvZXhpc3RlbmNlIgoKICAjIENvbG9yIHBhbGV0dGVzCiAgaW50ZXJhY3Rpb25fdHlwZSA8LSBjKCJleGNsdXNpb24iLCAiY29leGlzdGVuY2UiLCAibmV1dHJhbGl0eSIsICJtdXR1YWwgZXhjbHVzaW9uIiwgImZyZXF1ZW5jeS1kZXBlbmRlbnRcbmNvZXhpc3RlbmNlIikKICBteUNvbG9yID0gYygiI0RCNzQ2OSIsICIjNTU3QkFBIiwgIiM4NjUwQzQiLCAicmVkIiwgImJsdWUiKQogIG5hbWVzKG15Q29sb3IpIDwtIGludGVyYWN0aW9uX3R5cGUKCiAgIyBQbG90CiAgcGFpcnMgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUoCiAgICAgIEludGVyYWN0aW9uVHlwZSA9IG9yZGVyZWQoSW50ZXJhY3Rpb25UeXBlLCBjKCJleGNsdXNpb24iLCAiY29leGlzdGVuY2UiLCAibmV1dHJhbGl0eSIpKSwKICAgICAgSW50ZXJhY3Rpb25UeXBlRmluZXIgPSBvcmRlcmVkKEludGVyYWN0aW9uVHlwZUZpbmVyLCBjKCJjb21wZXRpdGl2ZSBleGNsdXNpb24iLCAibXV0dWFsIGV4Y2x1c2lvbiIsCiAgICAgICAgInN0YWJsZSBjb2V4aXN0ZW5jZSIsICJmcmVxdWVuY3ktZGVwZW5kZW50XG5jb2V4aXN0ZW5jZSIsICJuZXV0cmFsaXR5IikpKSAlPiUKICAgIGdyb3VwX2J5X2F0KC52YXJzID0gYyhiYXJfYnksIGZpbGxfYnkpKSAlPiUKICAgIHN1bW1hcml6ZShDb3VudCA9IG4oKSwgRnJhY3Rpb24gPSBuKCkvbnJvdyguKSkgJT4lCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX2JhcihhZXNfc3RyaW5nKHggPSBiYXJfYnksIHkgPSAiRnJhY3Rpb24iLCBmaWxsID0gZmlsbF9ieSksIHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9IDEsIHBvc2l0aW9uID0gImRvZGdlIikgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMSkpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG15Q29sb3IpICsKICAgIGZhY2V0X2dyaWQoYXMuZm9ybXVsYShwYXN0ZTAoIn4iLCBiYXJfYnkpKSwgc2NhbGUgPSAiZnJlZV94IikgKwogICAgeyBpZiAoc2hvd19maWxsX2xlZ2VuZCA9PSBGQUxTRSkgZ3VpZGVzKGZpbGwgPSAibm9uZSIpIH0gKwogICAgdGhlbWVfY293cGxvdCgpICsKICAgIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMCwgIm1tIiksCiAgICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkKfQoKYGBgCgoKRm91ciBleGFtcGxlIG91dGNvbWVzOiBiaXN0YWJpbGl0eSwgY29leGlzdGVuY2UsIGV4Y2x1c2lvbiwgYW5kIG5ldXRyYWxpdHkgCgpgYGB7cn0KcGFpcnNfZXhhbXBsZV9vdXRjb21lcyA8LSByZWFkX2NzdihoZXJlOjpoZXJlKCJkYXRhL291dHB1dC9wYWlyc19leGFtcGxlX291dGNvbWVzLmNzdiIpKQoKIyBQbG90IHBhaXJzIGV4YW1wbGUgZHluYW1pY3MKcF9wYWlyc19leGFtcGxlX291dGNvbWVzIDwtIHBhaXJzX2V4YW1wbGVfb3V0Y29tZXMgJT4lCiAgcGxvdF9wYWlyc19mcmVxKHBhaXJzX2ZyZXFfZGYgPSBwYWlyc19mcmVxLCBzaG93X3N0cmlwID0gRikgKwogIGZhY2V0X2dyaWQoLn5JbnRlcmFjdGlvblR5cGUpCgojIFRoZSBmcmVxdWVuY2llcyBvZiB0aHJlZSBvdXRjb21lcwpwX3BhaXJzX2ludGVyYWN0aW9uIDwtIHBsb3RfYmFyKHBhaXJzLCBiYXJfYnkgPSAiSW50ZXJhY3Rpb25UeXBlIikgKwogIGdlb21fdGV4dChkYXRhID0gZGF0YS5mcmFtZShJbnRlcmFjdGlvblR5cGUgPSAibmV1dHJhbGl0eSIsIHggPSAxLCB5ID0gMSwgbGFiZWwgPSAibiA9IDE4NiBwYWlycyIpLCBtYXBwaW5nID0gYWVzKHggPSB4LCB5ID0geSwgbGFiZWwgPSBsYWJlbCkpCmBgYAoKYGBge3IgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CnAgPC0gcGxvdF9ncmlkKHBfcGFpcnNfaW50ZXJhY3Rpb24sIHBfcGFpcnNfZXhhbXBsZV9vdXRjb21lcywgbmNvbCA9IDEsIGFsaWduID0gInYiLCByZWxfaGVpZ2h0cyA9IGMoMSwgMC41KSkKcApnZ3NhdmUoaGVyZTo6aGVyZSgib3V0cHV0L3JlcG9ydC9maWd1cmUvMDItcGFpcnMtcGFpcnNfb3V0Y29tZXMucGRmIiksIHAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKYGBgCgoKRm91ciBleGFtcGxlIG91dGNvbWVzOiBiaXN0YWJpbGl0eSwgY29leGlzdGVuY2UsIGV4Y2x1c2lvbiwgYW5kIG5ldXRyYWxpdHkgCgpgYGB7ciB3YXJuaW5nID0gRn0KcGFpcnNfZXhhbXBsZV9vdXRjb21lc19maW5lciA8LSByZWFkX2NzdihoZXJlOjpoZXJlKCJkYXRhL291dHB1dC9wYWlyc19leGFtcGxlX291dGNvbWVzX2ZpbmVyLmNzdiIpKQojIFBsb3QgcGFpcnMgZXhhbXBsZSBkeW5hbWljcwpwX3BhaXJzX2V4YW1wbGVfb3V0Y29tZXNfZmluZXIgPC0gcGFpcnNfZXhhbXBsZV9vdXRjb21lc19maW5lciAlPiUKICBwbG90X3BhaXJzX2ZyZXEocGFpcnNfZnJlcV9kZiA9IHBhaXJzX2ZyZXEsIHNob3dfc3RyaXAgPSBGKSArCiAgZmFjZXRfZ3JpZCgufkludGVyYWN0aW9uVHlwZUZpbmVyKQoKIyBUaGUgZnJlcXVlbmNpZXMgb2YgZml2ZSBmaW5lciBvdXRjb21lcwpwX3BhaXJzX2ludGVyYWN0aW9uX2ZpbmVyIDwtIHBsb3RfYmFyKHBhaXJzLCBiYXJfYnkgPSAiSW50ZXJhY3Rpb25UeXBlRmluZXIiLCBmaWxsX2J5ID0gIkludGVyYWN0aW9uVHlwZSIsIHNob3dfZmlsbF9sZWdlbmQgPSBUKQoKYGBgCgpgYGB7ciBmaWcud2lkdGggPSA1LCBmaWcuaGVpZ2h0ID0gM30KIyBDb21iaW5lIHBsb3QKI3RoZW1lX3NldCh0aGVtZV9jb3dwbG90KGZvbnRfc2l6ZT0xMikpCnAgPC0gcGxvdF9ncmlkKHBfcGFpcnNfaW50ZXJhY3Rpb25fZmluZXIsIHBfcGFpcnNfZXhhbXBsZV9vdXRjb21lc19maW5lciwgbmNvbCA9IDEsIGFsaWduID0gInYiLCByZWxfaGVpZ2h0cyA9IGMoMSwgMC40KSkKcApnZ3NhdmUoaGVyZTo6aGVyZSgib3V0cHV0L3JlcG9ydC9maWd1cmUvMDItcGFpcnMtcGFpcnNfb3V0Y29tZXMucGRmIiksIHAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKYGBgCgoKIyMgUGFpcnMgdGF4b25vbXkgdnMuIG91dGNvbWUgb2YgcGFpcndpc2UgY29tcGV0aXRpb24KCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyLXBhaXJzLTAzLXRheG9ub215LlIiKQpgYGAKCgojIyMgUkRQIHRheG9ub215CgpGZXJtZW50ZXIgdnMuIEludGVyYWN0aW9uIHR5cGUKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmxvYWQoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL3BhaXJzX2Jhcl9wbG90cy5SZGF0YSIpKQpwX3BhaXJzX2ludGVyYWN0aW9uX2Zlcm1lbnRlcgpnZ3NhdmUoaGVyZTo6aGVyZSgib3V0cHV0L3JlcG9ydC9maWd1cmUvMDItcGFpcnMtZmVybWVudGVyX2ludGVyYWN0aW9uLnBkZiIpLCBwX3BhaXJzX2ludGVyYWN0aW9uX2Zlcm1lbnRlciwgd2lkdGggPSA1LCBoZWlnaHQgPSA1KQoKYGBgCgpGYW1pbHkgdnMuIEludGVyYWN0aW9uIHR5cGUKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CnBfcGFpcnNfaW50ZXJhY3Rpb25fZmFtaWx5Cmdnc2F2ZShoZXJlOjpoZXJlKCJvdXRwdXQvcmVwb3J0L2ZpZ3VyZS8wMi1wYWlycy1mYW1pbHlfaW50ZXJhY3Rpb24ucGRmIiksIHBfcGFpcnNfaW50ZXJhY3Rpb25fZmFtaWx5LCB3aWR0aCA9IDUsIGhlaWdodCA9IDUpCmBgYAoKIyMjIFBhaXJ3aXNlIDE2UyBkaWZmZXJlbmNlcwoKUGFpcndpc2UgMTZTIGRpZmZlcmVuY2VzCgpgYGB7cn0KcGFpcnMgJT4lCiAgZmlsdGVyKCFpcy5uYShTZXFEaWZmZXJlbmNlKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IFNlcURpZmZlcmVuY2UsIGZpbGwgPSBQYWlyRmVybWVudGVyKSkgKwogIGdlb21faGlzdG9ncmFtKGNvbCA9ICJibGFjayIsIGJpbndpZHRoID0gMikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgbGFicyh4ID0gInBhaXJ3aXNlIDE2UyBiYXNlIHBhaXIgZGlmZmVyZW5jZXMiKSArCiAgZ2d0aXRsZSgiIikKYGBgCgpDb2Fyc2VkLWdyYWluZWQgMTZTIHNlcXVlbmNlIGRpZmZlcmVuY2UKCmBgYHtyfQpwYWlycyAlPiUKICBmaWx0ZXIoIWlzLm5hKFNlcURpZmZlcmVuY2UpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gU2VxRGlmZmVyZW5jZSwgZmlsbCA9IFBhaXJGZXJtZW50ZXIpKSArCiAgZ2VvbV9oaXN0b2dyYW0oY29sID0gImJsYWNrIiwgYmlud2lkdGggPSAxMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgbGFicyh4ID0gInBhaXJ3aXNlIDE2UyBiYXNlIHBhaXIgZGlmZmVyZW5jZXMiKSArCiAgZ2d0aXRsZSgiIikKCmBgYAoKCmBgYHtyIGluY2x1ZGUgPSBGfQojIDE2UyBzZXF1ZW5jZSBkaWZmZXJlbmNlIHZzLiBJbnRlcmFjdGlvbiB0eXBlCnBhaXJzX2ludGVyYWN0aW9uXzE2U19jdXQgJT4lCiAgZ2dwbG90KGFlcyh4ID0gU2VxRGlmZmVyZW5jZSwgeSA9IEZyYWNDb2V4dCkpICsKICBnZW9tX2NvbChjb2wgPSAiYmxhY2siLCBmaWxsID0gIndoaXRlIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpgYGAKCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQpwX3BhaXJzX2ludGVyYWN0aW9uXzE2U19jdXQKYGBgCgoKCiMgUmVsYXRpdmUgYWJ1bmRhbmNlIHdpdGhpbiBwYWlycyAKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyLXBhaXJzLTA0LXBhaXJzX3JlbGF0aXZlX2FidW5kYW5jZS5SIikKYGBgCgoKUmVsYXRpdmUgYWJ1bmRhbmNlIG9mIGZlcm1lbnRlciB2cy4gbm9uLWZlcm1lbnRlciBwYWlycwoKYGBge3J9CmxvYWQoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL3BhaXJzX2hpc3RfcGxvdHMuUmRhdGEiKSkKcGFpcnNfZnJlcV90YXhvbm9teV9mZXJtZW50ZXIgJT4lCiAgZmlsdGVyKFRpbWUgPT0gIlQ4IikgJT4lCiAgZmlsdGVyKCFJc29sYXRlMU1lYXN1cmVkRnJlcSAlaW4lIGMoMCwxKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gSXNvbGF0ZTFNZWFzdXJlZEZyZXEpLCBjb2wgPSAiYmxhY2siLCBmaWxsID0gIndoaXRlIikgKwogIGZhY2V0X2dyaWQoUGFpckZlcm1lbnRlcn4uLCBzY2FsZSA9ICJmcmVlIikgKwogIHRoZW1lX2J3KCkgKwogIGxhYnMoImZyZXF1ZW5jaWVzIG9mIGlzb2xhdGUgMSBhdCBUOCIpCmBgYAoKUmVsYXRpdmUgYWJ1bmRhbmNlIG9mIEVudGVyb2JhY3RlcmlhY2VhZSBhbmQgUHNldWRvbW9uYWRhY2VhZSBwYWlycwoKYGBge3J9CnBhaXJzX2ZyZXFfdGF4b25vbXlfZmFtaWx5ICU+JQogIGZpbHRlcihUaW1lID09ICJUOCIpICU+JQogIGZpbHRlcighSXNvbGF0ZTFNZWFzdXJlZEZyZXEgJWluJSBjKDAsMSkpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IElzb2xhdGUxTWVhc3VyZWRGcmVxKSwgY29sID0gImJsYWNrIiwgZmlsbCA9ICJ3aGl0ZSIpICsKICBmYWNldF9ncmlkKFBhaXJGYW1pbHl+Liwgc2NhbGUgPSAiZnJlZSIpICsKICB0aGVtZV9idygpICsKICBsYWJzKCJmcmVxdWVuY2llcyBvZiBpc29sYXRlIDEgYXQgVDgiKQoKYGBgCgoKCiMgRnJhY3Rpb24gb2YgcGFpcndpc2UgY29leGlzdGVuY2Ugd2l0aGluIGNvbW11bml0eSAgCgpgYGB7cn0KY29tbXVuaXRpZXNfcGFpcl9jb2V4dCA8LSBwYWlycyAlPiUKICBtdXRhdGUoQ29tbXVuaXR5ID0gb3JkZXJlZChDb21tdW5pdHksIGxldmVscyA9IGNvbW11bml0aWVzJENvbW11bml0eSkpICU+JQogIGZpbHRlcihJbnRlcmFjdGlvblR5cGUgIT0gIiIpICU+JQogIGZpbHRlcihJbnRlcmFjdGlvblR5cGUgJWluJSBjKCJleGNsdXNpb24iLCAiY29leGlzdGVuY2UiKSkgJT4lCiAgZ3JvdXBfYnkoQ29tbXVuaXR5LCBJbnRlcmFjdGlvblR5cGUpICU+JQogIHN1bW1hcml6ZShDb3VudCA9IG4oKSkgJT4lCiAgc3ByZWFkKEludGVyYWN0aW9uVHlwZSwgQ291bnQpICU+JQogIG11dGF0ZShGcmFjQ29leHQgPSBjb2V4aXN0ZW5jZSAvIChjb2V4aXN0ZW5jZSArIGV4Y2x1c2lvbikpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoQ29tbXVuaXR5U2l6ZSA9IGNvbW11bml0aWVzJENvbW11bml0eVNpemUpCgpjb21tdW5pdGllc19wYWlyX2NvZXh0JEZyYWNDb2V4dFtpcy5uYShjb21tdW5pdGllc19wYWlyX2NvZXh0JEZyYWNDb2V4dCldIDwtIDAKYGBgCgpGcmFjdGlvbiBvZiBjb2V4aXN0ZW5jZSBpbiAxMyBjb21tdW5pdGllcwoKYGBge3J9CnBfY29tbXVuaXRpZXNfcGFpcl9jb2V4dCA8LSAKY29tbXVuaXRpZXNfcGFpcl9jb2V4dCAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9iYXIoYWVzKHggPSBDb21tdW5pdHksIHkgPSBGcmFjQ29leHQpLCBzdGF0ID0gImlkZW50aXR5IiwgY29sID0gMSkgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsKICBsYWJzKHggPSAiY29tbXVuaXR5IiwgeSA9ICJmcmFjdGlvbiBvZiBjb2V4aXN0ZW5jZSIpCgpwX2NvbW11bml0aWVzX3BhaXJfY29leHQKZ2dzYXZlKCJmaWd1cmUvMDItY29tbXVuaXRpZXNfZnJhY3Rpb25fY29leGlzdGVuY2UucG5nIiwgcF9jb21tdW5pdGllc19wYWlyX2NvZXh0LCB3aWR0aCA9IDUsIGhlaWdodCA9IDMpCmBgYAoKIyBDb21tdW5pdHkgaGllcmFyY2h5IGluIGNvbW11bml0aWVzCgoKRnJvbSBIaWdnaW5zMjAxNywgdGhlIGNvbXBldGl0aXZlIHNjb3JlICRzX2kkIG9mIGVhY2ggc3RyYWluICRpJCB3YXMgZGVmaW5lZCBhcyBpdHMgbWVhbiBmcmFjdGlvbiAkZl97aWp9JCBhZnRlciBjby1jdWx0dXJlIHdpdGggZWFjaCBvZiB0aGUgJG4tMSQgY29tcGV0aXRvciBzdHJhaW5zOgoKJCRzX2k9KFxzdW1fe2lcbmVxIGp9Zl97aWp9KS8obi0xKSQkCgpUaGUgaGllcmFyY2h5IHNjb3JlICRoJCBmb3IgYW4gbi1tZW1iZXIgbmV0b3drciBpcyBjYWxjdWxhdGVkIGFzOgoKJCRoID0gXHN1bV97c19pPnNfan1mX3tpan0kJAoKYGBge3J9CmNvbW11bml0aWVzX2hpZXJhcmNoeSA8LSByZWFkX2NzdihoZXJlOjpoZXJlKCJkYXRhL3RlbXAvY29tbXVuaXRpZXNfaGllcmFyY2h5LmNzdiIpKQoKcF9jb21tdW5pdGllc19oaWVyYXJjaHkgPC0gY29tbXVuaXRpZXNfaGllcmFyY2h5ICU+JQogIGdncGxvdCgpICsKICBnZW9tX2JhcihhZXMoeCA9IENvbW11bml0eSwgeSA9IEhpZXJhcmNoeVNjb3JlKSwgc3RhdCA9ICJpZGVudGl0eSIsIGNvbCA9IDEpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAxKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKSArCiAgbGFicyh4ID0gImNvbW11bml0eSIsIHkgPSAiaGllcmFyY2h5IHNjb3JlIikKCnBfY29tbXVuaXRpZXNfaGllcmFyY2h5CnBkZihoZXJlOjpoZXJlKCJvdXRwdXQvZmlndXJlL2NvbW11bml0aWVzX2hpZXJhcmNoeS5wZGYiKSwgd2lkdGggPSA1LCBoZWlnaHQgPSAzKTsgcF9jb21tdW5pdGllc19oaWVyYXJjaHk7IGludmlzaWJsZShkZXYub2ZmKCkpCgogICAgCmBgYAoKCgoKIyBHcm93dGggdHJhaXRzIHZzIGNvZXhpc3RlbmNlIChEZXByZWNhdGVkKQoKYGBge3J9CmlmIChGQUxTRSkgewpzb3VyY2UoInNjcmlwdC8wMi1wYWlycy0wNS1ncm93dGhfcmF0ZXMuUiIpCnBhaXJzX2dyb3d0aF9yYXRlCnBfcGFpcnNfZ3Jvd3RoX3JhdGVfaGlzdApwX3BhaXJzX2dyb3d0aF9yYXRlX2RlbnNpdHkKCnBkZihoZXJlOjpoZXJlKCJvdXRwdXQvZmlndXJlL3BhaXJzX2dyb3d0aF9yYXRlc19oaXN0LnBkZiIpLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA1KTsgZm9yIChpIGluIDE6MTEpIHByaW50KHBfcGFpcnNfZ3Jvd3RoX3JhdGVfaGlzdF9saXN0W1tpXV0pOyBpbnZpc2libGUoZGV2Lm9mZigpKQoKcGRmKGhlcmU6OmhlcmUoIm91dHB1dC9maWd1cmUvcGFpcnNfZ3Jvd3RoX3JhdGVzX2RlbnNpdHkucGRmIiksIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpOyBmb3IgKGkgaW4gMToxMSkgcHJpbnQocF9wYWlyc19ncm93dGhfcmF0ZV9kZW5zaXR5X2xpc3RbW2ldXSk7IGludmlzaWJsZShkZXYub2ZmKCkpCn0KYGBgCgoKCgoKCgo=